-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 9/13/14, 3:31 AM, Anand Jain wrote: > > > Jeff, > > Nice patch. However its better if we do this in the btrfs kernel > function btrfs_scan_one_device(). Since the non-canonicalize path > can still sneak through the btrfs specific mount option "device=". > > Any comments ?
My initial reaction is to avoid playing naming names within the kernel. But since it's device mapper-specific, it might not be too messy to do that. In addition to the patch to the progs, we're also carrying a patch to systemd since it has it's own little ioctl wrapper to do the scanning. It needed to be fixed there as well. - -Jeff > Thanks, Anand > > > > On 06/05/2014 04:43 AM, Jeff Mahoney wrote: >> mount(8) will canonicalize pathnames before passing them to the >> kernel. Links to e.g. /dev/sda will be resolved to /dev/sda. >> Links to /dev/dm-# will be resolved using the name of the device >> mapper table to /dev/mapper/<name>. >> >> Btrfs will use whatever name the user passes to it, regardless of >> whether it is canonical or not. That means that if a 'btrfs >> device ready' is issued on any device node pointing to the >> original device, it will adopt the new name instead of the name >> that was used during mount. >> >> Mounting using /dev/sdb2 will result in df: /dev/sdb2 >> 209715200 39328 207577088 1% /mnt >> >> # ls -la /dev/whatever-i-like lrwxrwxrwx 1 root root 4 Jun 4 >> 13:36 /dev/whatever-i-like -> sdb2 # btrfs dev ready >> /dev/whatever-i-like # df /mnt /dev/whatever-i-like 209715200 >> 39328 207577088 1% /mnt >> >> Likewise, mounting with /dev/mapper/whatever and using /dev/dm-0 >> with a btrfs device command results in df showing /dev/dm-0. This >> can happen with multipath devices with friendly names enabled and >> doing something like 'partprobe' which (at least with our >> version) ends up issuing a 'change' uevent on the sysfs node. >> That *always* uses the dm-# name, and we get confused users. >> >> This patch does the same canonicalization of the paths that mount >> does so that we don't end up having inconsistent names reported >> by ->show_devices later. >> >> Signed-off-by: Jeff Mahoney <je...@suse.com> --- cmds-device.c | >> 60 ++++++++++++++++++++++++++++++++++++++++++++------------- >> cmds-replace.c | 13 ++++++++++-- utils.c | 57 >> ++++++++++++++++++++++++++++++++++++++++++++++++++++++ utils.h >> | 2 + 4 files changed, 117 insertions(+), 15 deletions(-) >> >> --- a/cmds-device.c +++ b/cmds-device.c @@ -95,6 +95,7 @@ static >> int cmd_add_dev(int argc, char ** int devfd, res; u64 >> dev_block_count = 0; int mixed = 0; + char *path; >> >> res = test_dev_for_mkfs(argv[i], force, estr); if (res) { @@ >> -118,15 +119,24 @@ static int cmd_add_dev(int argc, char ** goto >> error_out; } >> >> - strncpy_null(ioctl_args.name, argv[i]); + path = >> canonicalize_path(argv[i]); + if (!path) { + >> fprintf(stderr, + "ERROR: Could not canonicalize >> pathname '%s': %s\n", + argv[i], >> strerror(errno)); + ret++; + goto >> error_out; + } + + strncpy_null(ioctl_args.name, >> path); res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args); e = >> errno; - if(res<0){ + if (res < 0) { >> fprintf(stderr, "ERROR: error adding the device '%s' - %s\n", - >> argv[i], strerror(e)); + path, strerror(e)); >> ret++; } - + free(path); } >> >> error_out: @@ -242,6 +252,7 @@ static int cmd_scan_dev(int argc, >> char * >> >> for( i = devstart ; i < argc ; i++ ){ struct btrfs_ioctl_vol_args >> args; + char *path; >> >> if (!is_block_device(argv[i])) { fprintf(stderr, @@ -249,9 >> +260,17 @@ static int cmd_scan_dev(int argc, char * ret = 1; goto >> close_out; } - printf("Scanning for Btrfs filesystems in >> '%s'\n", argv[i]); + path = canonicalize_path(argv[i]); + >> if (!path) { + fprintf(stderr, + >> "ERROR: Could not canonicalize path '%s': %s\n", + >> argv[i], strerror(errno)); + ret = 1; + >> goto close_out; + } + printf("Scanning for Btrfs >> filesystems in '%s'\n", path); >> >> - strncpy_null(args.name, argv[i]); + >> strncpy_null(args.name, path); /* * FIXME: which are the error >> code returned by this ioctl ? * it seems that is impossible to >> understand if there no is @@ -262,9 +281,11 @@ static int >> cmd_scan_dev(int argc, char * >> >> if( ret < 0 ){ fprintf(stderr, "ERROR: unable to scan the device >> '%s' - %s\n", - argv[i], strerror(e)); + >> path, strerror(e)); + free(path); goto close_out; } + >> free(path); } >> >> close_out: @@ -284,6 +305,7 @@ static int cmd_ready_dev(int argc, >> char struct btrfs_ioctl_vol_args args; int fd; int ret; >> + char *path; >> >> if (check_argc_min(argc, 2)) usage(cmd_ready_dev_usage); @@ >> -293,22 +315,34 @@ static int cmd_ready_dev(int argc, char >> perror("failed to open /dev/btrfs-control"); return 1; } - if >> (!is_block_device(argv[1])) { + + path = >> canonicalize_path(argv[argc - 1]); + if (!path) { >> fprintf(stderr, - "ERROR: %s is not a block device\n", >> argv[1]); - close(fd); - return 1; + >> "ERROR: Could not canonicalize pathname '%s': %s\n", + >> argv[argc - 1], strerror(errno)); + ret = 1; + goto >> out; } >> >> - strncpy(args.name, argv[argc - 1], BTRFS_PATH_NAME_MAX); + >> if (!is_block_device(path)) { + fprintf(stderr, + >> "ERROR: %s is not a block device\n", path); + ret = 1; + >> goto out; + } + + strncpy(args.name, path, >> BTRFS_PATH_NAME_MAX); ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, >> &args); if (ret < 0) { fprintf(stderr, "ERROR: unable to >> determine if the device '%s'" - " is ready for >> mounting - %s\n", argv[argc - 1], + " is ready for >> mounting - %s\n", path, strerror(errno)); ret = 1; } >> >> +out: + free(path); close(fd); return ret; } --- >> a/cmds-replace.c +++ b/cmds-replace.c @@ -134,7 +134,7 @@ static >> int cmd_start_replace(int argc, c int fddstdev = -1; char *path; >> char *srcdev; - char *dstdev; + char *dstdev = NULL; int >> avoid_reading_from_srcdev = 0; int force_using_targetdev = 0; >> struct stat st; @@ -204,7 +204,12 @@ static int >> cmd_start_replace(int argc, c } >> >> srcdev = argv[optind]; - dstdev = argv[optind + 1]; + >> dstdev = canonicalize_path(argv[optind + 1]); + if (!dstdev) >> { + fprintf(stderr, + "ERROR: Could not >> canonicalize path '%s': %s\n", + argv[optind + 1], >> strerror(errno)); + } >> >> if (is_numerical(srcdev)) { struct btrfs_ioctl_fs_info_args >> fi_args; @@ -278,6 +283,8 @@ static int cmd_start_replace(int >> argc, c >> >> close(fddstdev); fddstdev = -1; + free(dstdev); + dstdev = >> NULL; >> >> dev_replace_handle_sigint(fdmnt); if (!do_not_background) { @@ >> -312,6 +319,8 @@ static int cmd_start_replace(int argc, c return >> 0; >> >> leave_with_error: + if (dstdev) + free(dstdev); if >> (fdmnt != -1) close(fdmnt); if (fdsrcdev != -1) --- a/utils.c +++ >> b/utils.c @@ -987,6 +987,63 @@ static int >> blk_file_in_dev_list(struct b } >> >> /* + * Resolve a pathname to a device mapper node to >> /dev/mapper/<name> + * Returns NULL on invalid input or malloc >> failure; Other failures + * will be handled by the caller using >> the input pathame. + */ +char *canonicalize_dm_name(const char >> *ptname) +{ + FILE *f; + size_t sz; + char >> path[256], name[256], *res = NULL; + + if (!ptname || >> !*ptname) + return NULL; + + snprintf(path, >> sizeof(path), "/sys/block/%s/dm/name", ptname); + if (!(f = >> fopen(path, "r"))) + return NULL; + + /* read <name>\n >> from sysfs */ + if (fgets(name, sizeof(name), f) && (sz = >> strlen(name)) > 1) { + name[sz - 1] = '\0'; + >> snprintf(path, sizeof(path), "/dev/mapper/%s", name); + + >> if (access(path, F_OK) == 0) + res = strdup(path); + >> } + fclose(f); + return res; +} + +/* + * Resolve a >> pathname to a canonical device node, e.g. /dev/sda1 or + * to a >> device mapper pathname. + * Returns NULL on invalid input or >> malloc failure; Other failures + * will be handled by the caller >> using the input pathame. + */ +char *canonicalize_path(const char >> *path) +{ + char *canonical, *p; + + if (!path || !*path) + >> return NULL; + + canonical = realpath(path, NULL); + if >> (!canonical) + return strdup(path); + p = >> strrchr(canonical, '/'); + if (p && strncmp(p, "/dm-", 4) == 0 >> && isdigit(*(p + 4))) { + char *dm = >> canonicalize_dm_name(p + 1); + if (dm) { + >> free(canonical); + return dm; + } + } + >> return canonical; +} + +/* * returns 1 if the device was mounted, >> < 0 on error or 0 if everything * is safe to continue. */ --- >> a/utils.h +++ b/utils.h @@ -61,6 +61,8 @@ int >> btrfs_add_to_fsid(struct btrfs_trans int btrfs_scan_for_fsid(int >> run_ioctls); void btrfs_register_one_device(char *fname); int >> btrfs_scan_one_dir(char *dirname, int run_ioctl); +char >> *canonicalize_dm_name(const char *ptname); +char >> *canonicalize_path(const char *path); int check_mounted(const >> char *devicename); int check_mounted_where(int fd, const char >> *file, char *where, int size, struct btrfs_fs_devices >> **fs_devices_mnt); >> > -- To unsubscribe from this list: send the line "unsubscribe > linux-btrfs" in the body of a message to majord...@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > - -- Jeff Mahoney SUSE Labs -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.22 (Darwin) iQIcBAEBAgAGBQJUFhr9AAoJEB57S2MheeWyXzgQAMKR0b29uU0kyYbalOxjpVkB yAvR5kFItcEgRSfUUyqJqL+atJZ2PrzU4fQsz6i25cOBfQC5EdZYO/QENXe7HleU oCECYucZC14qTLwswhpMeCtyMrX98sjhQxZ6NPSmLZWi/Btc2QDdwwbij4B3KRnQ lE/AWmtT/J0fqlmjr18ETdTjTCZVyxUpN809hZpHAwQAiDZhXqbTUveaFu3DpTyn vDdM5LZ2oGPjS/3WgoNiFy36R1cnxIh3k/+aM/afU20T//dOn8Cdrh+k868hv9fV f3YfkyoHzwBCXp8VaOZytkOy7HCLbTEpnnB7MbvrNo1ukOlrFZRVRMSUrco2QD6x 4UYfgBj/zuzxIUZotEnpAmE8ppbMBylqjx+dyIwviDCU0Huw9mEnraBf3Yunuf3k za92pv/SYJnEFRl2w5ULhtR6GJ3RM8TQJOtWRJjPLkS3L30xvVOQZ1zXoazi/4yX qp7bKKN/hzC8mPvp8aoCW5c+F652e4pmUplbR4RDaNCD7ipv60XfQBVYOJOGh2YX +OCYERzFs4th3uPlKNDSfsLHwGY36bPC3mPdiaJW144MX1vHL5YKJiEKcnk5QZNY BwWidSvdylitAmZeKeCRTOJJh/b+Q7/K72RdWSl6g5qipa/00Gc97Sl/jNOyZ7K6 URPW75jcC/KtA2gIArtL =fAyc -----END PGP SIGNATURE----- -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html