linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Eric Sandeen <sandeen@redhat.com>
To: Eric Sandeen <sandeen@redhat.com>
Cc: linux-btrfs@vger.kernel.org
Subject: Re: [PATCH 4/4] btrfs-progs: rework get_fs_info to remove side effects
Date: Mon, 11 Mar 2013 17:27:08 -0500	[thread overview]
Message-ID: <513E5A3C.4080309@redhat.com> (raw)
In-Reply-To: <1363043581-15812-5-git-send-email-sandeen@redhat.com>

On 3/11/13 6:13 PM, Eric Sandeen wrote:
> get_fs_info() has been silently switching from a device to a mounted
> path as needed; the caller's filehandle was unexpectedly closed &
> reopened outside the caller's scope.  Not so great.
> 
> The callers do want "fdmnt" to be the filehandle for the mount point
> in all cases, though - the various ioctls act on this (not on an fd
> for the device).  But switching it in the local scope of get_fs_info
> is incorrect; it just so happens that *usually* the fd number is
> unchanged.
> 
> So - use the new helpers to detect when an argument is a block
> device, and open the the mounted path more obviously / explicitly
> for ioctl use, storing the filehandle in fdmnt.
> 
> Then, in get_fs_info, ignore the fd completely, and use the path on
> the argument to determine if the caller wanted to act on just that
> device, or on all devices for the filesystem.
> 
> Affects those commands which are documented to accept either
> a block device or a path:

Following my tradition I'll (immediately) self-nak this one for now.

After I sent this I thought to test:

# mkfs.btrfs /dev/sdb1 /dev/sdb2; mount /dev/sdb1 /mnt/test; btrfs stats /dev/sdb2

after I tested it, and that fails where it used to work.  So

a) we could use a test for this, and 
b) I broke something

If the overall idea of the change seems decent, I'll get it fixed up after I sort
out what I broke.  :/

-Eric

> * btrfs device stats
> * btrfs replace start
> * btrfs scrub start
> * btrfs scrub status
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---
>  cmds-device.c  |    5 ++-
>  cmds-replace.c |    6 +++-
>  cmds-scrub.c   |   10 ++++---
>  utils.c        |   73 +++++++++++++++++++++++++++++++++++++++----------------
>  utils.h        |    2 +-
>  5 files changed, 66 insertions(+), 30 deletions(-)
> 
> diff --git a/cmds-device.c b/cmds-device.c
> index 58df6da..41e79d3 100644
> --- a/cmds-device.c
> +++ b/cmds-device.c
> @@ -321,13 +321,14 @@ static int cmd_dev_stats(int argc, char **argv)
>  
>  	path = argv[optind];
>  
> -	fdmnt = open_file_or_dir(path);
> +	fdmnt = open_path_or_dev_mnt(path);
> +
>  	if (fdmnt < 0) {
>  		fprintf(stderr, "ERROR: can't access '%s'\n", path);
>  		return 12;
>  	}
>  
> -	ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
> +	ret = get_fs_info(path, &fi_args, &di_args);
>  	if (ret) {
>  		fprintf(stderr, "ERROR: getting dev info for devstats failed: "
>  				"%s\n", strerror(-ret));
> diff --git a/cmds-replace.c b/cmds-replace.c
> index 10030f6..6397bb5 100644
> --- a/cmds-replace.c
> +++ b/cmds-replace.c
> @@ -168,7 +168,9 @@ static int cmd_start_replace(int argc, char **argv)
>  	if (check_argc_exact(argc - optind, 3))
>  		usage(cmd_start_replace_usage);
>  	path = argv[optind + 2];
> -	fdmnt = open_file_or_dir(path);
> +
> +	fdmnt = open_path_or_dev_mnt(path);
> +
>  	if (fdmnt < 0) {
>  		fprintf(stderr, "ERROR: can't access \"%s\": %s\n",
>  			path, strerror(errno));
> @@ -215,7 +217,7 @@ static int cmd_start_replace(int argc, char **argv)
>  		}
>  		start_args.start.srcdevid = (__u64)atoi(srcdev);
>  
> -		ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
> +		ret = get_fs_info(path, &fi_args, &di_args);
>  		if (ret) {
>  			fprintf(stderr, "ERROR: getting dev info for devstats failed: "
>  					"%s\n", strerror(-ret));
> diff --git a/cmds-scrub.c b/cmds-scrub.c
> index e5fccc7..52264f1 100644
> --- a/cmds-scrub.c
> +++ b/cmds-scrub.c
> @@ -1101,13 +1101,14 @@ static int scrub_start(int argc, char **argv, int resume)
>  
>  	path = argv[optind];
>  
> -	fdmnt = open_file_or_dir(path);
> +	fdmnt = open_path_or_dev_mnt(path);
> +
>  	if (fdmnt < 0) {
>  		ERR(!do_quiet, "ERROR: can't access '%s'\n", path);
>  		return 12;
>  	}
>  
> -	ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
> +	ret = get_fs_info(path, &fi_args, &di_args);
>  	if (ret) {
>  		ERR(!do_quiet, "ERROR: getting dev info for scrub failed: "
>  		    "%s\n", strerror(-ret));
> @@ -1558,13 +1559,14 @@ static int cmd_scrub_status(int argc, char **argv)
>  
>  	path = argv[optind];
>  
> -	fdmnt = open_file_or_dir(path);
> +	fdmnt = open_path_or_dev_mnt(path);
> +
>  	if (fdmnt < 0) {
>  		fprintf(stderr, "ERROR: can't access to '%s'\n", path);
>  		return 12;
>  	}
>  
> -	ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
> +	ret = get_fs_info(path, &fi_args, &di_args);
>  	if (ret) {
>  		fprintf(stderr, "ERROR: getting dev info for scrub failed: "
>  				"%s\n", strerror(-ret));
> diff --git a/utils.c b/utils.c
> index 4bf457f..27cec56 100644
> --- a/utils.c
> +++ b/utils.c
> @@ -717,7 +717,7 @@ int open_path_or_dev_mnt(const char *path)
>  			errno = EINVAL;
>  			return -1;
>  		}
> -		fdmnt = open(mp, O_RDWR);
> +		fdmnt = open_file_or_dir(mp);
>  	} else
>  		fdmnt = open_file_or_dir(path);
>  
> @@ -1544,9 +1544,20 @@ int get_device_info(int fd, u64 devid,
>  	return ret ? -errno : 0;
>  }
>  
> -int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
> +/*
> + * For a given path, fill in the ioctl fs_ and info_ args.
> + * If the path is a btrfs mountpoint, fill info for all devices.
> + * If the path is a btrfs device, fill in only that device.
> + *
> + * The path provided must be either on a mounted btrfs fs,
> + * or be a mounted btrfs device.
> + *
> + * Returns 0 on success, or a negative errno.
> + */
> +int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args,
>  		struct btrfs_ioctl_dev_info_args **di_ret)
>  {
> +	int fd = -1;
>  	int ret = 0;
>  	int ndevs = 0;
>  	int i = 1;
> @@ -1556,33 +1567,50 @@ int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
>  
>  	memset(fi_args, 0, sizeof(*fi_args));
>  
> -	ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args);
> -	if (ret && (errno == EINVAL || errno == ENOTTY)) {
> -		/* path is not a mounted btrfs. Try if it's a device */
> +	if (is_block_device(path)) {
> +		/* Ensure it's mounted, then set path to the mountpoint */
> +		fd = open(path, O_RDONLY);
> +		if (fd < 0) {
> +			ret = -errno;
> +			fprintf(stderr, "Couldn't open %s: %s\n",
> +				path, strerror(errno));
> +			goto out;
> +		}
>  		ret = check_mounted_where(fd, path, mp, sizeof(mp),
>  					  &fs_devices_mnt);
> -		if (!ret)
> -			return -EINVAL;
> -		if (ret < 0)
> -			return ret;
> +		if (ret < 0) {
> +			fprintf(stderr, "Couldn't get mountpoint for %s: %s\n",
> +				path, strerror(-ret));
> +			goto out;
> +		}
> +		path = mp;
> +		/* Only fill in this one device */
>  		fi_args->num_devices = 1;
>  		fi_args->max_id = fs_devices_mnt->latest_devid;
>  		i = fs_devices_mnt->latest_devid;
>  		memcpy(fi_args->fsid, fs_devices_mnt->fsid, BTRFS_FSID_SIZE);
> -		close(fd);
> -		fd = open_file_or_dir(mp);
> -		if (fd < 0)
> -			return -errno;
> -	} else if (ret) {
> -		return -errno;
> +	}
> +
> +	fd = open_file_or_dir(path);
> +	if (fd < 0) {
> +		ret = -errno;
> +		goto out;
> +	}
> +		
> +	ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args);
> +	if (ret < 0) {
> +		ret = -errno;
> +		goto out;
>  	}
>  
>  	if (!fi_args->num_devices)
> -		return 0;
> +		goto out;
>  
>  	di_args = *di_ret = malloc(fi_args->num_devices * sizeof(*di_args));
> -	if (!di_args)
> -		return -errno;
> +	if (!di_args) {
> +		ret = -errno;
> +		goto out;
> +	}
>  
>  	for (; i <= fi_args->max_id; ++i) {
>  		BUG_ON(ndevs >= fi_args->num_devices);
> @@ -1590,13 +1618,16 @@ int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
>  		if (ret == -ENODEV)
>  			continue;
>  		if (ret)
> -			return ret;
> +			goto out;
>  		ndevs++;
>  	}
>  
>  	BUG_ON(ndevs == 0);
> -
> -	return 0;
> +	ret = 0;
> +out:
> +	if (fd != -1)
> +		close(fd);
> +	return ret;
>  }
>  
>  #define isoctal(c)	(((c) & ~7) == '0')
> diff --git a/utils.h b/utils.h
> index 8e0252b..885b9c5 100644
> --- a/utils.h
> +++ b/utils.h
> @@ -50,7 +50,7 @@ u64 parse_size(char *s);
>  int open_file_or_dir(const char *fname);
>  int get_device_info(int fd, u64 devid,
>  		    struct btrfs_ioctl_dev_info_args *di_args);
> -int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
> +int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args,
>  		struct btrfs_ioctl_dev_info_args **di_ret);
>  int get_label(const char *btrfs_dev);
>  int set_label(const char *btrfs_dev, const char *label);
> 


  reply	other threads:[~2013-03-11 22:27 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-11 23:12 [PATCH 0/4] smalle cleanup + get_fs_info rework Eric Sandeen
2013-03-11 23:12 ` [PATCH 1/4] btrfs-progs: close fd on return from label get/set functions Eric Sandeen
2013-03-11 23:12 ` [PATCH 2/4] btrfs-progs: three new device/path helpers Eric Sandeen
2013-03-11 23:13 ` [PATCH 3/4] btrfs-progs: don't open-code mountpoint discovery in scrub cancel Eric Sandeen
2013-03-11 23:13 ` [PATCH 4/4] btrfs-progs: rework get_fs_info to remove side effects Eric Sandeen
2013-03-11 22:27   ` Eric Sandeen [this message]
2013-03-12  4:17   ` [PATCH 4/4 V2] " Eric Sandeen
2013-03-12 16:40     ` David Sterba
2013-03-12 17:30       ` David Sterba

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=513E5A3C.4080309@redhat.com \
    --to=sandeen@redhat.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).