summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-11-18 11:26:35 -0500
committerChris Mason <chris.mason@oracle.com>2008-11-18 11:26:35 -0500
commit6c771595afad6e04c25b5adaea8ffbbbfe9c728c (patch)
tree57abff520ec457c8493c2d9ccaf7696fb51196be
parent4d1d3a59d6debe80ce1e2da60e82233ab8f1f886 (diff)
downloadbtrfs-progs-6c771595afad6e04c25b5adaea8ffbbbfe9c728c.tar.gz
Modify the subvol and snapshot creation ioctls to work anywhere in the tree
This changes the snapshot and subvol ioctl API and command lines so that new snapshots and subvols can be created anywhere. Subvolume creation hasn't changed much: btrfsctl -S subvol_name directory This creates a new subvolume under 'directory' Snapshot creation looks the same, but is actually different: btrfsctl -s full_path_to_new_snapshot file_or_dir For example: btrfsctl -s /mnt/new_snap /mnt/subvol Will create a new snapshot named new_snap under /mnt of the root found in /mnt/subvol. It always snapshots the entire root regardless of which file or directory inside the root you give it. Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--btrfsctl.c102
-rw-r--r--ioctl.h8
2 files changed, 81 insertions, 29 deletions
diff --git a/btrfsctl.c b/btrfsctl.c
index 82c5f30d..e0497992 100644
--- a/btrfsctl.c
+++ b/btrfsctl.c
@@ -28,6 +28,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
+#include <libgen.h>
#include "kerncompat.h"
#include "ctree.h"
#include "transaction.h"
@@ -48,8 +49,8 @@ void print_usage(void)
printf(" [-r size] [-A device] [-a] [-c]\n");
printf("\t-d filename: defragments one file\n");
printf("\t-d directory: defragments the entire Btree\n");
- printf("\t-s snap_name: existing_subvol creates a new snapshot\n");
- printf("\t-s snap_name: tree_root creates a new subvolume\n");
+ printf("\t-s snap_name dir: creates a new snapshot of dir\n");
+ printf("\t-S subvol_name dir: creates a new subvolume\n");
printf("\t-r [+-]size[gkm]: resize the FS by size amount\n");
printf("\t-A device: scans the device file for a Btrfs filesystem\n");
printf("\t-a: scans all devices for Btrfs filesystems\n");
@@ -58,18 +59,47 @@ void print_usage(void)
exit(1);
}
+int open_file_or_dir(char *fname)
+{
+ int ret;
+ struct stat st;
+ DIR *dirstream;
+ int fd;
+
+ ret = stat(fname, &st);
+ if (ret < 0) {
+ perror("stat:");
+ exit(1);
+ }
+ if (S_ISDIR(st.st_mode)) {
+ dirstream = opendir(fname);
+ if (!dirstream) {
+ perror("opendir");
+ exit(1);
+ }
+ fd = dirfd(dirstream);
+ } else {
+ fd = open(fname, O_RDWR);
+ }
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+ return fd;
+}
int main(int ac, char **av)
{
- char *fname;
+ char *fname = NULL;
+ char *snap_location = NULL;
+ int snap_fd = 0;
int fd;
int ret;
struct btrfs_ioctl_vol_args args;
char *name = NULL;
int i;
- struct stat st;
- DIR *dirstream;
unsigned long command = 0;
int len;
+ char *fullpath;
if (ac == 2 && strcmp(av[1], "-a") == 0) {
fprintf(stderr, "Scanning for Btrfs filesystems\n");
@@ -82,8 +112,17 @@ int main(int ac, char **av)
fprintf(stderr, "-s requires an arg");
print_usage();
}
- name = av[i + 1];
+ fullpath = av[i + 1];
+
+ snap_location = strdup(fullpath);
+ snap_location = dirname(snap_location);
+
+ snap_fd = open_file_or_dir(snap_location);
+
+ name = strdup(fullpath);
+ name = basename(name);
len = strlen(name);
+
if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
fprintf(stderr,
"snapshot name zero length or too long\n");
@@ -95,6 +134,24 @@ int main(int ac, char **av)
exit(1);
}
command = BTRFS_IOC_SNAP_CREATE;
+ } else if (strcmp(av[i], "-S") == 0) {
+ if (i + 1 >= ac - 1) {
+ fprintf(stderr, "-S requires an arg");
+ print_usage();
+ }
+ name = av[i + 1];
+ len = strlen(name);
+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
+ fprintf(stderr,
+ "snapshot name zero length or too long\n");
+ exit(1);
+ }
+ if (strchr(name, '/')) {
+ fprintf(stderr,
+ "error: / not allowed in names\n");
+ exit(1);
+ }
+ command = BTRFS_IOC_SUBVOL_CREATE;
} else if (strcmp(av[i], "-d") == 0) {
if (i >= ac - 1) {
fprintf(stderr, "-d requires an arg\n");
@@ -129,33 +186,24 @@ int main(int ac, char **av)
exit(1);
}
fname = av[ac - 1];
- ret = stat(fname, &st);
- if (ret < 0) {
- perror("stat:");
- exit(1);
- }
- if (S_ISDIR(st.st_mode)) {
- dirstream = opendir(fname);
- if (!dirstream) {
- perror("opendir");
- exit(1);
- }
- fd = dirfd(dirstream);
- } else if (command == BTRFS_IOC_SCAN_DEV) {
+
+ if (command == BTRFS_IOC_SCAN_DEV) {
fd = open("/dev/btrfs-control", O_RDWR);
name = fname;
- } else {
- fd = open(fname, O_RDWR);
- }
- if (fd < 0) {
- perror("open");
- exit(1);
- }
+ } else {
+ fd = open_file_or_dir(fname);
+ }
+
if (name)
strcpy(args.name, name);
else
args.name[0] = '\0';
- ret = ioctl(fd, command, &args);
+
+ if (command == BTRFS_IOC_SNAP_CREATE) {
+ args.fd = fd;
+ ret = ioctl(snap_fd, command, &args);
+ } else
+ ret = ioctl(fd, command, &args);
if (ret < 0) {
perror("ioctl:");
exit(1);
diff --git a/ioctl.h b/ioctl.h
index 85ed35a7..5fb2ad18 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -18,13 +18,15 @@
#ifndef __IOCTL_
#define __IOCTL_
+#include <asm/types.h>
#include <linux/ioctl.h>
#define BTRFS_IOCTL_MAGIC 0x94
#define BTRFS_VOL_NAME_MAX 255
-#define BTRFS_PATH_NAME_MAX 4095
+#define BTRFS_PATH_NAME_MAX 3072
struct btrfs_ioctl_vol_args {
+ __s64 fd;
char name[BTRFS_PATH_NAME_MAX + 1];
};
@@ -51,5 +53,7 @@ struct btrfs_ioctl_vol_args {
struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_BALANCE _IOW(BTRFS_IOCTL_MAGIC, 12, \
struct btrfs_ioctl_vol_args)
-
+/* 13 is for CLONE_RANGE */
+#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
+ struct btrfs_ioctl_vol_args)
#endif