* [RFC][PATCH] BTRFS_PROG: mount.btrfs helper
@ 2013-11-03 18:38 Goffredo Baroncelli
2013-11-03 18:38 ` [PATCH] Provide " Goffredo Baroncelli
2013-11-03 21:23 ` [RFC][PATCH] BTRFS_PROG: " Jeff Mahoney
0 siblings, 2 replies; 4+ messages in thread
From: Goffredo Baroncelli @ 2013-11-03 18:38 UTC (permalink / raw)
To: linux-btrfs
Hi all,
this patch provides a mount.btrfs helper for the mount command to
mounting a btrfs filesystem.
A btrfs filesystem could spans several disks. This helper scans all
the partition to discover all the disks required to mount a filesystem.
So it is not necessary any-more to "scan" manually the partitions to mount
a filesystem via the "btrfs device scan" command.
It adds in the option parameters the devices required to mount a
filesystem. Supposing that a filesystem is composed by several disks
(/dev/sd[cdef]), when the user does "mount /dev/sdd /mnt", mount calls
mount.btrfs which int turn calls the mount(2) syscall like:
mount("/dev/sdd", "/mnt", "btrfs", 0,
"device=/dev/sdc,device=/dev/sde,device=/de/vsdf").
This helper uses both the libblkid and libmount to discover the
devices, to compute the parameters manipulation and to update the mtab
file.
I got the idea from the btrfs.wiki; its biggest gains is to avoid the
separation of scanning phases (at boot time or during the block device
discovery) from the mounting. Also mkfs.btrfs could avoid to re-do a
rescan of the devices after a formatting.
mount.btrfs doesn't add more requirement than the mount command. It
would be possible to remove the "btrfs" command from the initramfs, and
all the related scripts (in my debian both udev and btrfs-tools
packages contains three udev rules for btrfs).
Comments are welcome.
--
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D 17B2 0EDA 9B37 8B82 E0B5
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH] Provide mount.btrfs helper
2013-11-03 18:38 [RFC][PATCH] BTRFS_PROG: mount.btrfs helper Goffredo Baroncelli
@ 2013-11-03 18:38 ` Goffredo Baroncelli
2013-11-03 21:23 ` [RFC][PATCH] BTRFS_PROG: " Jeff Mahoney
1 sibling, 0 replies; 4+ messages in thread
From: Goffredo Baroncelli @ 2013-11-03 18:38 UTC (permalink / raw)
To: linux-btrfs; +Cc: Goffredo Baroncelli
This patch provides a mount.btrfs helper for the mount command to mounting a
btrfs filesystem.
A btrfs filesystem could span several disks. This helper scans all the
partition to discover all the disks required to mount a filesystem.
So it is not necessary any-more to "scan" the partitions to mount a filesystem.
It adds in the option parameters the devices required to mount a filesystem.
Supposing that a filesystem is composed by several disks (/dev/sd[cdef]), when
the user does "mount /dev/sdd /mnt", mount calls mount.btrfs which int turn
calls the mount(2) so:
mount("/dev/sdd", "/mnt", "btrfs", 0, "device=/dev/sdc,device=/dev/sde,device=/de/vsdf").
This helper uses both the libblkid and libmount to discover the devices, to
compute the parameters manipulation and to update the mtab file.
I got the idea from the btrfs.wiki; its biggest gains is to avoid the
separation of scanning phases (at boot time or during the block device
discovery) from the mounting. Also mkfs.btrfs could avoid to re-do a rescan of
the devices after a formatting.
mount.btrfs doesn't add more requirement than the mount command. It would be
possible to remove the "btrfs" command from the initramfs, and all the related
scripts (in my debian both udev and btrfs-tools packages contains three udev
rules for btrfs).
---
Makefile | 6 +-
btrfs-mount.c | 617 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 622 insertions(+), 1 deletion(-)
create mode 100644 btrfs-mount.c
diff --git a/Makefile b/Makefile
index c43cb68..974e8ad 100644
--- a/Makefile
+++ b/Makefile
@@ -45,7 +45,7 @@ MAKEOPTS = --no-print-directory Q=$(Q)
progs = mkfs.btrfs btrfs-debug-tree btrfsck \
btrfs btrfs-map-logical btrfs-image btrfs-zero-log btrfs-convert \
- btrfs-find-root btrfstune btrfs-show-super
+ btrfs-find-root btrfstune btrfs-show-super mount.btrfs
# external libs required by various binaries; for btrfs-foo,
# specify btrfs_foo_libs = <list of libs>; see $($(subst...)) rules below
@@ -171,6 +171,10 @@ ioctl-test: $(objects) $(libs) ioctl-test.o
@echo " [LD] $@"
$(Q)$(CC) $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS)
+mount.btrfs: btrfs-mount.o
+ @echo " [LD] $@"
+ $(Q)$(CC) $(CFLAGS) -o mount.btrfs -lmount -lblkid btrfs-mount.o $(LDFLAGS)
+
send-test: $(objects) $(libs) send-test.o
@echo " [LD] $@"
$(Q)$(CC) $(CFLAGS) -o send-test $(objects) send-test.o $(LDFLAGS) $(LIBS) -lpthread
diff --git a/btrfs-mount.c b/btrfs-mount.c
new file mode 100644
index 0000000..fe07f9e
--- /dev/null
+++ b/btrfs-mount.c
@@ -0,0 +1,617 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <blkid/blkid.h>
+#include <libmount/libmount.h>
+
+#define MOUNT_FLAG_FAKE_MOUNT 1
+#define MOUNT_FLAG_VERBOSE 2
+#define MOUNT_FLAG_NOT_WRITIING_MTAB 4
+#define MOUNT_FLAG_IGNORE_SLOPPY_OPTS 8
+
+struct btrfs_device {
+ char *device_name;
+ char *device_uuid;
+ char *fs_name;
+ char *fs_uuid;
+ struct btrfs_device *next;
+};
+
+/* Parse program args, and set the related variables */
+static int parse_args(int argc, char **argv, char **options,
+ char **spec, char **dir, int *flag)
+{
+ char opt;
+
+ *options = NULL;
+
+ while ((opt = getopt(argc, argv, "sfnvo:")) != -1) {
+
+ switch (opt) {
+
+ case 's': /* tolerate sloppy mount options */
+ *flag |= MOUNT_FLAG_IGNORE_SLOPPY_OPTS;
+ break;
+ case 'f': /* fake mount */
+ *flag |= MOUNT_FLAG_FAKE_MOUNT;
+ break;
+ case 'n': /* mount without writing in mtab */
+ *flag |= MOUNT_FLAG_NOT_WRITIING_MTAB;
+ break;
+ case 'v': /* verbose */
+ *flag |= MOUNT_FLAG_VERBOSE;
+ break;
+ case 'o':
+ *options = optarg;
+ break;
+ default:
+ fprintf( stderr,"ERROR: unknown option: '%c'\n", opt);
+ return 1;
+ }
+ }
+
+ if (argc-optind != 2) {
+ fprintf(stderr, "ERROR: two arguments are needed\n");
+ return 1;
+ }
+
+ *spec = argv[optind];
+ *dir = argv[optind+1];
+
+ return 0;
+
+}
+
+/* add a new string to the string array */
+static void add_to_list(struct btrfs_device **head, struct btrfs_device *d)
+{
+ d->next = (*head);
+ *head = d;
+}
+
+/* free a btrfs_device struct */
+static void free_btrfs_device(struct btrfs_device *p)
+{
+ if (!p) return;
+
+ free( p->device_name );
+ free( p->device_uuid );
+ free( p->fs_name );
+ free( p->fs_uuid );
+ free(p);
+}
+
+/* free a btrfs devices(s) list */
+static void free_btrfs_devices_list(struct btrfs_device **p)
+{
+ while (*p) {
+ struct btrfs_device *next;
+ next = (*p)->next;
+ free_btrfs_device(*p);
+ *p = next;
+ }
+}
+
+/*
+ * this function extracts information from a device
+ */
+static int get_btrfs_dev_info(const char *devname, struct btrfs_device **device)
+{
+ int rc, ret=0;
+ blkid_probe pr;
+
+ *device = NULL;
+
+ pr = blkid_new_probe_from_filename(devname);
+ if (!pr) {
+ fprintf(stderr, "ERROR: faild to create a new libblkid "
+ "probe for '%s'\n", devname);
+ return 1;
+ }
+
+ /* enable topology probing */
+ blkid_probe_enable_superblocks(pr, 1);
+
+ /* set all flags */
+ blkid_probe_set_superblocks_flags(pr,
+ BLKID_SUBLKS_LABEL |
+ BLKID_SUBLKS_UUID |
+ BLKID_SUBLKS_TYPE );
+
+ rc = blkid_do_safeprobe(pr);
+ if (rc == -1) {
+ fprintf(stderr, "ERROR: blkid_do_safeprobe() failed for '%s'\n",
+ devname);
+ ret = 2;
+ } else if (rc == 1) {
+ fprintf(stderr, "ERROR: cannot gather information about "
+ "superblocks for '%s'\n", devname);
+ ret = 3;
+ } else {
+ int i, nvals = blkid_probe_numof_values(pr);
+
+ *device = calloc(sizeof(struct btrfs_device), 1);
+ if (!*device) {
+ fprintf(stderr, "ERROR: not enough memory!\n");
+ ret = 20;
+ goto quit;
+ }
+ (*device)->device_name = strdup(devname);
+ if (!(*device)->device_name) {
+ fprintf(stderr, "ERROR: not enough memory!\n");
+ ret = 21;
+ goto quit;
+ }
+ for (i = 0; i < nvals; i++) {
+ const char *name, *data;
+ blkid_probe_get_value(pr, i, &name, &data, NULL);
+
+ if (!strcmp("UUID_SUB", name)) {
+ (*device)->device_uuid = strdup(data);
+ if ((*device)->device_uuid)
+ continue;
+ fprintf(stderr,
+ "ERROR: not enough memory!\n");
+ ret = 22;
+ goto quit;
+ } else if (!strcmp("UUID", name)) {
+ (*device)->fs_uuid = strdup(data);
+ if ((*device)->fs_uuid)
+ continue;
+ fprintf(stderr,
+ "ERROR: not enough memory!\n");
+ ret = 23;
+ goto quit;
+ } else if (!strcmp("LABEL", name)) {
+ (*device)->fs_name = strdup(data);
+ if ((*device)->fs_name)
+ continue;
+ fprintf(stderr,
+ "ERROR: not enough memory!\n");
+ ret = 24;
+ goto quit;
+ } else if (!strcmp("TYPE", name) &&
+ strcmp(data, "btrfs")) {
+
+ fprintf(stderr, "ERROR: scanning a non-btrfs"
+ " device (%s)\n", devname);
+ ret = 25;
+ goto quit;
+ }
+ }
+ }
+quit:
+ /* if failed, clean *device memory allocation */
+ if (ret && *device) {
+ free_btrfs_device(*device);
+ *device = NULL;
+ }
+ blkid_free_probe(pr);
+ return ret;
+}
+
+/* check if path is a valid block device */
+static int is_block_device(char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st))
+ return 0;
+
+ return S_ISBLK(st.st_mode);
+}
+
+/*
+ * this function get all the devices related to a filesystem
+ * return values:
+ * 0 -> OK
+ * >0 -> error
+ * <0 -> cache incoerency
+ */
+static int _get_devices_list(int flag, char *spec,
+ struct btrfs_device **devices, blkid_cache *bcache)
+{
+ /*blkid_cache bcache;*/
+ blkid_dev_iterate bit;
+ blkid_dev bdev;
+
+ char *dev;
+ struct btrfs_device *device0;
+ struct btrfs_device *d, *prevd;
+ int ret;
+
+ *devices = NULL;
+
+ if (!strncmp(spec, "LABEL=", 6)) {
+ dev = blkid_evaluate_tag("LABEL", spec+6, bcache);
+ } else if (!strncmp(spec, "UUID=", 5)) {
+ dev = blkid_evaluate_tag("UUID", spec+5, bcache);
+ } else {
+ dev = spec;
+ }
+
+ if (!dev || !is_block_device(dev)) {
+ fprintf(stderr, "ERROR: '%s' is not a valid block device\n",
+ spec);
+ return 2;
+ }
+
+ if (flag & MOUNT_FLAG_VERBOSE)
+ printf("INFO: start from device %s\n", dev);
+
+ if (flag & MOUNT_FLAG_VERBOSE)
+ printf("INFO: scan the first device\n");
+
+ ret = get_btrfs_dev_info(dev, &device0);
+ if (ret)
+ /* the error messages was already emitted */
+ return 3;
+
+ bit = blkid_dev_iterate_begin(*bcache);
+ if (blkid_dev_set_search(bit, "UUID", device0->fs_uuid)) {
+ fprintf(stderr,"ERROR: unable to setup blkid_dev_set_search()\n");
+ ret = 4;
+ goto exit;
+ }
+
+ while (!blkid_dev_next(bit, &bdev)) {
+ const char *dev;
+
+ struct btrfs_device *p;
+ dev = blkid_dev_devname(bdev);
+
+ if (get_btrfs_dev_info(dev, &p)) {
+ /* the error messages was already emitted */
+ ret = 5;
+ goto exit;
+ }
+ if (strcmp(device0->fs_uuid, p->fs_uuid)) {
+ /* cache incoherency */
+ free_btrfs_devices_list(devices);
+ *devices = NULL;
+ ret = -1;
+ goto exit;
+ };
+ add_to_list(devices, p);
+ }
+
+ /* sort the list so dev is the first device */
+ for (prevd = NULL, d = *devices ; d ; prevd = d, d = d->next) {
+ if (strcmp(d->device_name, dev))
+ continue;
+ if (!prevd)
+ /* ok, dev is the first device: do nothing */
+ break;
+
+ prevd->next = d->next;
+ d->next = *devices;
+ *devices = d;
+ }
+
+exit:
+ if (ret && *devices) {
+ free_btrfs_devices_list(devices);
+ *devices = NULL;
+ }
+
+ blkid_dev_iterate_end(bit);
+ free_btrfs_device(device0);
+
+ return ret;
+}
+
+/*
+ * this function get all the devices related to a filesystem
+ * return values:
+ * 0 -> OK
+ * >0 -> error
+ */
+static int get_devices_list(int flag, char *spec,
+ struct btrfs_device **devices)
+{
+ blkid_cache bcache;
+ int ret;
+
+ if (blkid_get_cache(&bcache, NULL)) {
+ fprintf(stderr, "ERROR: cannot get blkid cache\n");
+ return 1;
+ }
+
+ ret = _get_devices_list(flag, spec, devices, &bcache);
+ /*
+ * If ret < 0 a cache inchoernecy was detected
+ * if ret == 0 and *devices == 0, still a cache inchoernecy
+ * was detected: anyway we rebuild the cache and retry a new serach
+ */
+ if (ret < 0 || (!ret && !*devices)) {
+ if (blkid_probe_all(bcache)) {
+ fprintf(stderr,
+ "ERROR: cannot do a blkid_probe_all()\n");
+ ret = 6;
+ goto exit;
+ }
+ ret = _get_devices_list(flag, spec, devices, &bcache);
+ }
+
+exit:
+ blkid_put_cache(bcache);
+ return ret;
+}
+
+/* joins two options string */
+static int join_options(char **dst, char *fs_opts, char *vfs_opts)
+{
+ int l1=0, l2=0;
+
+ if (fs_opts && *fs_opts)
+ l1 = strlen(fs_opts);
+
+ if (vfs_opts && *vfs_opts)
+ l2 = strlen(vfs_opts);
+
+ if (!l1 && !l2) {
+ *dst = strdup("");
+ return *dst == NULL;
+ }
+
+ *dst = calloc(l1+l2+2, 1);
+ if (!*dst)
+ return 3;
+
+ if (l1) {
+ strcpy(*dst, fs_opts);
+ strcat(*dst, ",");
+ }
+ if (l2)
+ strcat(*dst, vfs_opts);
+
+ return 0;
+}
+
+/*
+ * This function rearrange the options
+ * 1) removes from "options":
+ * - the vfs_options (which became bits in mount_flags)
+ * - eventually device=<xxx> options passed (these aren't used)
+ * 2) adds to "options" a true list of device=<xxx>
+ * 3) put all the options in all_options, which will be used in
+ * updating mtab
+ */
+static int rearrange_options(int flags, char **options,
+ unsigned long *mount_flags,
+ char **all_options,
+ struct btrfs_device *devices)
+{
+ int rc;
+ char *user_opts=NULL, *vfs_opts=NULL, *fs_opts=NULL;
+ char *value=NULL;
+ int ret=0;
+ size_t size;
+ struct btrfs_device *device;
+
+ *all_options = NULL;
+
+ rc = mnt_split_optstr(*options, &user_opts, &vfs_opts, &fs_opts, 0, 0);
+ if (rc) {
+ fprintf(stderr, "ERROR: not enough memory\n");
+ ret = 1;
+ goto exit;
+ }
+
+ rc = mnt_optstr_get_flags(vfs_opts, mount_flags,
+ mnt_get_builtin_optmap(MNT_LINUX_MAP));
+ if (rc) {
+ fprintf(stderr, "ERROR: not enough memory\n");
+ ret = 2;
+ goto exit;
+ }
+
+ /* removes devices */
+ while (!mnt_optstr_get_option(fs_opts, "device", &value, &size)) {
+ rc = mnt_optstr_remove_option(&fs_opts, "device");
+ if (rc) {
+ fprintf(stderr, "ERROR: not enough memory\n");
+ ret = 3;
+ goto exit;
+ }
+ if (flags & MOUNT_FLAG_IGNORE_SLOPPY_OPTS) {
+ fprintf(stderr, "WARNING: 'device=' option ignored\n");
+ continue;
+ }
+ fprintf(stderr, "ERROR: 'device=' option not allowed\n");
+ ret=7;
+ goto exit;
+
+ }
+ /* append additional devices */
+ device = devices->next;
+ while (device) {
+ rc = mnt_optstr_append_option(&fs_opts,
+ "device", device->device_name);
+ if (rc) {
+ fprintf(stderr, "ERROR: not enough memory\n");
+ ret = 4;
+ goto exit;
+ }
+ device = device->next;
+ }
+
+ if (join_options(all_options, fs_opts, vfs_opts)) {
+ fprintf(stderr, "ERROR: not enough memory\n");
+ ret = 4;
+ goto exit;
+ }
+
+ *options = fs_opts;
+ fs_opts = NULL;
+
+ if (flags & MOUNT_FLAG_VERBOSE) {
+ printf("INFO: final flags: %s\n", *options);
+ printf("INFO: all flags : %s\n", *all_options);
+ }
+
+exit:
+ free(vfs_opts);
+ free(fs_opts);
+ free(user_opts);
+ return ret;
+
+}
+
+/* this function update the mtab file (if needed */
+static int update_mtab(int flags, char *device, char *target, char *all_opts )
+{
+
+ struct libmnt_fs *fs = NULL;
+ struct libmnt_update *update = NULL;
+
+ char *vfs_opts = NULL;
+ int ret = 0, rc;
+
+ fs = mnt_new_fs();
+ if (!fs)
+ goto memoryerror;
+ if (mnt_fs_set_options(fs, all_opts))
+ goto memoryerror;
+ if (mnt_fs_set_source(fs, device))
+ goto memoryerror;
+ if (mnt_fs_set_target(fs, target))
+ goto memoryerror;
+ if (mnt_fs_set_fstype(fs, "btrfs"))
+ goto memoryerror;
+ if (flags & MOUNT_FLAG_VERBOSE)
+ printf("INFO: info for updating 'mtab' prepared\n");
+ if (!(update = mnt_new_update()))
+ goto memoryerror;
+
+ rc = mnt_update_set_fs(update, 0, NULL, fs);
+
+ if (rc == 1) {
+ fprintf(stderr, "WARNING: update of mtab not needed\n");
+ ret = 0;
+ goto exit;
+ } else if (rc) {
+ fprintf(stderr, "ERROR: failed to set fs\n");
+ ret = 10;
+ goto exit;
+ }
+
+ ret = mnt_update_table(update, NULL);
+ if (ret)
+ fprintf(stderr, "ERROR: failed to update mtab\n");
+ else if (flags & MOUNT_FLAG_VERBOSE)
+ printf("INFO: 'mtab' updated\n");
+ goto exit;
+
+memoryerror:
+ fprintf(stderr, "ERROR: not enough memory\n");
+ if (fs) mnt_free_fs(fs);
+ if (update) mnt_free_update(update);
+
+ free(vfs_opts);
+
+ return 100;
+
+exit:
+ if (fs) mnt_free_fs(fs);
+ if (update) mnt_free_update(update);
+
+ free(vfs_opts);
+
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+
+ char *fs_opts, *spec, *dir, *all_options;
+ int ret, flags=0;
+ struct btrfs_device *devices;
+ unsigned long mount_flags = 0;
+
+ ret = parse_args(argc, argv, &fs_opts, &spec, &dir, &flags);
+
+ if (ret)
+ goto internalerror;
+
+ if (flags & MOUNT_FLAG_VERBOSE)
+ printf("INFO: parsed arguments\n");
+
+ ret = get_devices_list(flags, spec, &devices);
+ if (ret)
+ goto internalerror;
+
+ assert(devices);
+
+ if (flags & MOUNT_FLAG_VERBOSE)
+ printf("INFO: extracted the devices list\n");
+
+ if (flags & MOUNT_FLAG_VERBOSE) {
+ struct btrfs_device *d;
+ printf("INFO: filesystem info:\n");
+ printf("INFO:\tUUID=%s\n", devices->fs_uuid);
+ printf("INFO:\tLABEL=%s\n", devices->fs_name);
+ for (d = devices ; d ; d=d->next)
+ printf("INFO:\tUUID_SUB=%s - dev=%s\n",
+ d->device_uuid, d->device_name);
+ }
+
+ ret = rearrange_options(flags, &fs_opts, &mount_flags, &all_options,
+ devices);
+ if (ret)
+ goto internalerror;
+
+ if (!(flags & MOUNT_FLAG_FAKE_MOUNT)) {
+ int e;
+
+ if (flags & MOUNT_FLAG_VERBOSE) {
+ char *vfs_opts=NULL;
+ printf("INFO: source: %s\n", devices->device_name);
+ printf("INFO: target: %s\n", dir);
+ mnt_optstr_apply_flags(&vfs_opts, mount_flags,
+ mnt_get_builtin_optmap(MNT_LINUX_MAP));
+ printf("INFO: vfs_opts: 0x%08lx - %s\n",
+ mount_flags, vfs_opts);
+ printf("INFO: fs_opts: %s\n", fs_opts);
+ free(vfs_opts);
+ }
+
+ if (!(flags & MOUNT_FLAG_NOT_WRITIING_MTAB)) {
+ ret = update_mtab(flags, devices->device_name, dir,
+ all_options);
+ /* update_mtab error messages alredy printed */
+ if (ret)
+ goto errormtab;
+ }
+
+ ret = mount(devices->device_name, dir, "btrfs", mount_flags,
+ fs_opts);
+ e = errno;
+ if (!ret) {
+ if (flags & MOUNT_FLAG_VERBOSE)
+ printf("INFO: mount succeded\n");
+ } else {
+ fprintf(stderr, "ERROR: mount failed : %d - %s\n",
+ e, strerror(e));
+ }
+
+ } else {
+ ret = 0;
+ }
+
+ exit(ret);
+
+errormtab:
+ exit(16);
+
+internalerror:
+ exit(2);
+
+}
\ No newline at end of file
--
1.8.4.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [RFC][PATCH] BTRFS_PROG: mount.btrfs helper
2013-11-03 18:38 [RFC][PATCH] BTRFS_PROG: mount.btrfs helper Goffredo Baroncelli
2013-11-03 18:38 ` [PATCH] Provide " Goffredo Baroncelli
@ 2013-11-03 21:23 ` Jeff Mahoney
2013-11-03 23:07 ` Goffredo Baroncelli
1 sibling, 1 reply; 4+ messages in thread
From: Jeff Mahoney @ 2013-11-03 21:23 UTC (permalink / raw)
To: Goffredo Baroncelli, linux-btrfs
[-- Attachment #1: Type: text/plain, Size: 2187 bytes --]
On 11/3/13, 1:38 PM, Goffredo Baroncelli wrote:
> Hi all,
>
> this patch provides a mount.btrfs helper for the mount command to
> mounting a btrfs filesystem.
> A btrfs filesystem could spans several disks. This helper scans all
> the partition to discover all the disks required to mount a filesystem.
> So it is not necessary any-more to "scan" manually the partitions to mount
> a filesystem via the "btrfs device scan" command.
>
> It adds in the option parameters the devices required to mount a
> filesystem. Supposing that a filesystem is composed by several disks
> (/dev/sd[cdef]), when the user does "mount /dev/sdd /mnt", mount calls
> mount.btrfs which int turn calls the mount(2) syscall like:
> mount("/dev/sdd", "/mnt", "btrfs", 0,
> "device=/dev/sdc,device=/dev/sde,device=/de/vsdf").
>
> This helper uses both the libblkid and libmount to discover the
> devices, to compute the parameters manipulation and to update the mtab
> file.
>
> I got the idea from the btrfs.wiki; its biggest gains is to avoid the
> separation of scanning phases (at boot time or during the block device
> discovery) from the mounting. Also mkfs.btrfs could avoid to re-do a
> rescan of the devices after a formatting.
>
> mount.btrfs doesn't add more requirement than the mount command. It
> would be possible to remove the "btrfs" command from the initramfs, and
> all the related scripts (in my debian both udev and btrfs-tools
> packages contains three udev rules for btrfs).
>
> Comments are welcome.
I like the idea but I'm concerned how well this will perform on large
systems with thousands of disks attached. btrfs dev scan can have a list
of potential devices specified, but this helper defaults to all devices.
A quick test run with 2000 scsi_debug targets shows that btrfs dev scan
can take 8 seconds, and that's with no actual I/O occurring. I don't
think we want to specify the list of devices to scan on the mount
command line, but perhaps an /etc config file that limits the scan to a
list of devices (and defaults to all) similar to how mdadm.conf works
would be a good improvement.
-Jeff
--
Jeff Mahoney
SUSE Labs
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 841 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC][PATCH] BTRFS_PROG: mount.btrfs helper
2013-11-03 21:23 ` [RFC][PATCH] BTRFS_PROG: " Jeff Mahoney
@ 2013-11-03 23:07 ` Goffredo Baroncelli
0 siblings, 0 replies; 4+ messages in thread
From: Goffredo Baroncelli @ 2013-11-03 23:07 UTC (permalink / raw)
To: Jeff Mahoney; +Cc: linux-btrfs
On 2013-11-03 22:23, Jeff Mahoney wrote:
> On 11/3/13, 1:38 PM, Goffredo Baroncelli wrote:
>> Hi all,
>>
>> this patch provides a mount.btrfs helper for the mount command to
>> mounting a btrfs filesystem.
>> A btrfs filesystem could spans several disks. This helper scans all
>> the partition to discover all the disks required to mount a filesystem.
>> So it is not necessary any-more to "scan" manually the partitions to mount
>> a filesystem via the "btrfs device scan" command.
>>
>> It adds in the option parameters the devices required to mount a
>> filesystem. Supposing that a filesystem is composed by several disks
>> (/dev/sd[cdef]), when the user does "mount /dev/sdd /mnt", mount calls
>> mount.btrfs which int turn calls the mount(2) syscall like:
>> mount("/dev/sdd", "/mnt", "btrfs", 0,
>> "device=/dev/sdc,device=/dev/sde,device=/de/vsdf").
>>
>> This helper uses both the libblkid and libmount to discover the
>> devices, to compute the parameters manipulation and to update the mtab
>> file.
>>
>> I got the idea from the btrfs.wiki; its biggest gains is to avoid the
>> separation of scanning phases (at boot time or during the block device
>> discovery) from the mounting. Also mkfs.btrfs could avoid to re-do a
>> rescan of the devices after a formatting.
>>
>> mount.btrfs doesn't add more requirement than the mount command. It
>> would be possible to remove the "btrfs" command from the initramfs, and
>> all the related scripts (in my debian both udev and btrfs-tools
>> packages contains three udev rules for btrfs).
>>
>> Comments are welcome.
>
> I like the idea but I'm concerned how well this will perform on large
> systems with thousands of disks attached. btrfs dev scan can have a list
> of potential devices specified, but this helper defaults to all devices.
liblkid uses a cache to increase the speed of a search.
Only if some incoherency from the data is found (like a mkfs after a
boot) a "probe all" is executed.
But in this case we could update mkfs.btrfs to invalidate the blkid
cache of disks involved (which should be done in any case)
> A quick test run with 2000 scsi_debug targets shows that btrfs dev scan
> can take 8 seconds, and that's with no actual I/O occurring. I don't
> think we want to specify the list of devices to scan on the mount
> command line, but perhaps an /etc config file that limits the scan to a
> list of devices (and defaults to all) similar to how mdadm.conf works
> would be a good improvement.
I tried in qemu-kvm:
# btrfs device scan # it took about 8sec
# modprobe scsi_debug num_tgts=2000 # 8 seconds were required
# before all udev instances ended
But when I performed a blkid -c /dev/null (which should rebuild the
cache) it takes ages....
I have to investigate a bit...
> -Jeff
BR
G.Baroncelli
>
--
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D 17B2 0EDA 9B37 8B82 E0B5
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-11-04 5:38 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-03 18:38 [RFC][PATCH] BTRFS_PROG: mount.btrfs helper Goffredo Baroncelli
2013-11-03 18:38 ` [PATCH] Provide " Goffredo Baroncelli
2013-11-03 21:23 ` [RFC][PATCH] BTRFS_PROG: " Jeff Mahoney
2013-11-03 23:07 ` Goffredo Baroncelli
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).