From: Miao Xie <miaox@cn.fujitsu.com>
To: Linux Btrfs <linux-btrfs@vger.kernel.org>
Subject: [RFC PATCH 9/9] Btrfs: get write access for adding device
Date: Mon, 26 Nov 2012 16:51:36 +0800 [thread overview]
Message-ID: <50B32D98.20309@cn.fujitsu.com> (raw)
In-Reply-To: <50B32ABF.7040803@cn.fujitsu.com>
Without this patch, we can add a device into the R/O fs.
Steps to reproduce:
# mkfs.btrfs -d single -m single <disk0> <disk1>
# mount -o ro <disk0> <mnt0>
# mount -o ro <disk0> <mnt1>
# mount -o remount,rw <mnt0>
# umount <mnt0>
# btrfs device add <disk1> <mnt1>
It is because we just check the R/O flag of the super block object.
It is not enough, because the kernel may set the R/O flag only for
the mount point. We need invoke
mnt_want_write_file()
to do the full check.
But, this interface is also used for the seed fs, so I split it to
two functions, one is used for the common fs, and the other is for
the seed fs. The detail fix method is following:
- When we mount a seed fs, we doesn't return -EACCESS. Instead, we just
set R/O flag for the super block, and tell the user that "the fs is a
seed fs, we mount it on R/O state" by printk
- If the fs is not a seed fs, we invoke the common device add function,
which will call mnt_want_write_file() at first and get write access.
- If the fs is a seed fs, we will check the flags of the mount point.
- If it is R/O, it means the users mount the fs on R/O state on their
own initiative, in other words, the users don't want to change anything
include adding a new device. So in this case, we will return -EROFS.
- If the R/O flag of the mount point is not set, we will make a new fs which
is based on the seed fs and add the device into it. At the end of this
process, we will clear R/O flag of the super block, and then we can
access the new fs freely.
In this way,
- We will forbid adding/removing any device to/from a filesystem which is
mounted on R/O state(mount -o ro), even it is a seed filesystem. In short,
the new process follows the read-only rule more strictly.
- We can modify the new filesystem which is based on a seed filesystem
immediately after it is created, needn't do remount/umount-mount.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++--------
fs/btrfs/super.c | 5 ++--
fs/btrfs/volumes.c | 26 ++++++------------
fs/btrfs/volumes.h | 3 +-
4 files changed, 83 insertions(+), 32 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index e6525d1..650d82d 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2218,13 +2218,14 @@ out:
return ret;
}
-static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
+static int btrfs_common_add_device(struct file *file, struct btrfs_root *root,
+ const char *devname)
{
- struct btrfs_ioctl_vol_args *vol_args;
int ret;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
+ ret = mnt_want_write_file(file);
+ if (ret)
+ return ret;
mutex_lock(&root->fs_info->volume_mutex);
if (root->fs_info->balance_ctl) {
@@ -2233,18 +2234,76 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
goto out;
}
- vol_args = memdup_user(arg, sizeof(*vol_args));
- if (IS_ERR(vol_args)) {
- ret = PTR_ERR(vol_args);
+ ret = btrfs_init_new_device(root, devname, false);
+out:
+ mutex_unlock(&root->fs_info->volume_mutex);
+ return ret;
+}
+
+static int btrfs_seed_add_device(struct file *file, struct btrfs_root *root,
+ const char *devname)
+{
+ struct super_block *sb = root->fs_info->sb;
+ int ret;
+
+ sb_start_write(sb);
+
+ mutex_lock(&root->fs_info->volume_mutex);
+ /*
+ * Some one may add a new device into a seed fs, and make a
+ * new fs, so let's add the device by the common method.
+ */
+ if (!root->fs_info->fs_devices->seeding) {
+ mutex_unlock(&root->fs_info->volume_mutex);
+ sb_end_write(sb);
+ return btrfs_common_add_device(file, root, devname);
+ }
+
+ down_write(&sb->s_umount);
+ if (file->f_path.mnt->mnt_flags & MNT_READONLY) {
+ ret = -EROFS;
goto out;
}
- vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
- ret = btrfs_init_new_device(root, vol_args->name);
+ if (root->fs_info->balance_ctl) {
+ printk(KERN_INFO "btrfs: balance in progress\n");
+ ret = -EINVAL;
+ goto out;
+ }
- kfree(vol_args);
+ ret = btrfs_init_new_device(root, devname, true);
+ if (!ret) {
+ sb->s_flags &= ~MS_RDONLY;
+ printk(KERN_INFO "Btrfs created a new filesystem based on "
+ "seed filesystem.");
+ }
out:
+ up_write(&sb->s_umount);
mutex_unlock(&root->fs_info->volume_mutex);
+ sb_end_write(sb);
+ return ret;
+}
+
+static long btrfs_ioctl_add_dev(struct file *file, void __user *arg)
+{
+ struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+ struct btrfs_ioctl_vol_args *vol_args;
+ int ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ vol_args = memdup_user(arg, sizeof(*vol_args));
+ if (IS_ERR(vol_args))
+ return PTR_ERR(vol_args);
+ vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
+
+ if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_SEEDING)
+ ret = btrfs_seed_add_device(file, root, vol_args->name);
+ else
+ ret = btrfs_common_add_device(file, root, vol_args->name);
+
+ kfree(vol_args);
return ret;
}
@@ -3800,7 +3859,7 @@ long btrfs_ioctl(struct file *file, unsigned int
case BTRFS_IOC_RESIZE:
return btrfs_ioctl_resize(file, argp);
case BTRFS_IOC_ADD_DEV:
- return btrfs_ioctl_add_dev(root, argp);
+ return btrfs_ioctl_add_dev(file, argp);
case BTRFS_IOC_RM_DEV:
return btrfs_ioctl_rm_dev(file, argp);
case BTRFS_IOC_FS_INFO:
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 915ac14..621fd3c 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1116,8 +1116,9 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
goto error_fs_info;
if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
- error = -EACCES;
- goto error_close_devices;
+ flags |= MS_RDONLY;
+ printk(KERN_INFO "Btrfs detected seed filesystem, force it to "
+ "be READONLY\n");
}
bdev = fs_devices->latest_bdev;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 0f5ebb7..66d6dd6 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1568,6 +1568,7 @@ static int btrfs_prepare_sprout(struct btrfs_root *root)
super_flags = btrfs_super_flags(disk_super) &
~BTRFS_SUPER_FLAG_SEEDING;
btrfs_set_super_flags(disk_super, super_flags);
+ root->fs_info->fs_state &= ~BTRFS_SUPER_FLAG_SEEDING;
return 0;
}
@@ -1648,32 +1649,25 @@ error:
return ret;
}
-int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
+int btrfs_init_new_device(struct btrfs_root *root, const char *device_path,
+ bool seed_fs)
{
struct request_queue *q;
struct btrfs_trans_handle *trans;
struct btrfs_device *device;
struct block_device *bdev;
struct list_head *devices;
- struct super_block *sb = root->fs_info->sb;
struct rcu_string *name;
u64 total_bytes;
- int seeding_dev = 0;
int ret = 0;
- if ((sb->s_flags & MS_RDONLY) && !root->fs_info->fs_devices->seeding)
- return -EROFS;
-
bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,
root->fs_info->bdev_holder);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
- if (root->fs_info->fs_devices->seeding) {
- seeding_dev = 1;
- down_write(&sb->s_umount);
+ if (seed_fs)
mutex_lock(&uuid_mutex);
- }
filemap_write_and_wait(bdev->bd_inode->i_mapping);
@@ -1740,8 +1734,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
device->mode = FMODE_EXCL;
set_blocksize(device->bdev, 4096);
- if (seeding_dev) {
- sb->s_flags &= ~MS_RDONLY;
+ if (seed_fs) {
ret = btrfs_prepare_sprout(root);
BUG_ON(ret); /* -ENOMEM */
}
@@ -1776,7 +1769,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
total_bytes + 1);
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
- if (seeding_dev) {
+ if (seed_fs) {
ret = init_first_rw_device(trans, root, device);
if (ret) {
btrfs_abort_transaction(trans, root, ret);
@@ -1806,9 +1799,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info);
ret = btrfs_commit_transaction(trans, root);
- if (seeding_dev) {
+ if (seed_fs) {
mutex_unlock(&uuid_mutex);
- up_write(&sb->s_umount);
if (ret) /* transaction commit */
return ret;
@@ -1837,10 +1829,8 @@ error_trans:
kfree(device);
error:
blkdev_put(bdev, FMODE_EXCL);
- if (seeding_dev) {
+ if (seed_fs)
mutex_unlock(&uuid_mutex);
- up_write(&sb->s_umount);
- }
return ret;
}
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 53c06af..a76d598 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -279,7 +279,8 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
u8 *uuid, u8 *fsid);
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
-int btrfs_init_new_device(struct btrfs_root *root, char *path);
+int btrfs_init_new_device(struct btrfs_root *root, const char *path,
+ bool seed_fs);
int btrfs_balance(struct btrfs_balance_control *bctl,
struct btrfs_ioctl_balance_args *bargs);
int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info);
--
1.7.11.7
next prev parent reply other threads:[~2012-11-26 8:51 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-11-26 8:39 [PATCH 0/9] random fix for btrfs_ioctl() Miao Xie
2012-11-26 8:40 ` [PATCH 1/9] Btrfs: pass root object into btrfs_ioctl_{start, wait}_sync() Miao Xie
2012-11-26 8:41 ` [PATCH 2/9] Btrfs: don't start a new transaction when starting sync Miao Xie
2012-11-26 8:42 ` [PATCH 3/9] Btrfs: fix wrong return value of btrfs_wait_for_commit() Miao Xie
2012-11-26 8:43 ` [PATCH 4/9] Btrfs: get write access when setting the default subvolume Miao Xie
2012-11-26 8:43 ` [PATCH 5/9] Btrfs: get write access when doing resize fs Miao Xie
2012-11-26 8:44 ` [PATCH 6/9] Btrfs: get write access when removing a device Miao Xie
2012-11-26 8:48 ` [PATCH 7/9] Btrfs: get write access for scrub Miao Xie
2012-11-26 8:50 ` [PATCH 8/9] Btrfs: get write access for qgroup operations Miao Xie
2012-11-26 8:51 ` Miao Xie [this message]
2012-12-12 2:52 ` [RFC PATCH 9/9] Btrfs: get write access for adding device Miao Xie
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=50B32D98.20309@cn.fujitsu.com \
--to=miaox@cn.fujitsu.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).