* [PATCH 1/9] Btrfs: pass root object into btrfs_ioctl_{start, wait}_sync()
2012-11-26 8:39 [PATCH 0/9] random fix for btrfs_ioctl() Miao Xie
@ 2012-11-26 8:40 ` Miao Xie
2012-11-26 8:41 ` [PATCH 2/9] Btrfs: don't start a new transaction when starting sync Miao Xie
` (7 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2012-11-26 8:40 UTC (permalink / raw)
To: Linux Btrfs
Since we have gotten the root in the caller, just pass it into
btrfs_ioctl_{start, wait}_sync() directly.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 84bb4de..fd3fff5 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3038,9 +3038,9 @@ long btrfs_ioctl_trans_end(struct file *file)
return 0;
}
-static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp)
+static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
+ void __user *argp)
{
- struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root;
struct btrfs_trans_handle *trans;
u64 transid;
int ret;
@@ -3061,9 +3061,9 @@ static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp
return 0;
}
-static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp)
+static noinline long btrfs_ioctl_wait_sync(struct btrfs_root *root,
+ void __user *argp)
{
- struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root;
u64 transid;
if (argp) {
@@ -3770,9 +3770,9 @@ long btrfs_ioctl(struct file *file, unsigned int
btrfs_sync_fs(file->f_dentry->d_sb, 1);
return 0;
case BTRFS_IOC_START_SYNC:
- return btrfs_ioctl_start_sync(file, argp);
+ return btrfs_ioctl_start_sync(root, argp);
case BTRFS_IOC_WAIT_SYNC:
- return btrfs_ioctl_wait_sync(file, argp);
+ return btrfs_ioctl_wait_sync(root, argp);
case BTRFS_IOC_SCRUB:
return btrfs_ioctl_scrub(root, argp);
case BTRFS_IOC_SCRUB_CANCEL:
--
1.7.11.7
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 2/9] Btrfs: don't start a new transaction when starting sync
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 ` Miao Xie
2012-11-26 8:42 ` [PATCH 3/9] Btrfs: fix wrong return value of btrfs_wait_for_commit() Miao Xie
` (6 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2012-11-26 8:41 UTC (permalink / raw)
To: Linux Btrfs
If there is no running transaction in the fs, we needn't start a new one when
we want to start sync.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 14 ++++++++++----
fs/btrfs/transaction.c | 13 ++++++++-----
2 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index fd3fff5..5102747 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3045,16 +3045,22 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
u64 transid;
int ret;
- trans = btrfs_start_transaction(root, 0);
- if (IS_ERR(trans))
- return PTR_ERR(trans);
+ trans = btrfs_attach_transaction(root);
+ if (IS_ERR(trans)) {
+ if (PTR_ERR(trans) != -ENOENT)
+ return PTR_ERR(trans);
+
+ /* No running transaction, don't bother */
+ transid = root->fs_info->last_trans_committed;
+ goto out;
+ }
transid = trans->transid;
ret = btrfs_commit_transaction_async(trans, root, 0);
if (ret) {
btrfs_end_transaction(trans, root);
return ret;
}
-
+out:
if (argp)
if (copy_to_user(argp, &transid, sizeof(transid)))
return -EFAULT;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 04bbfb1..350e9c4 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -1309,9 +1309,10 @@ static void do_async_commit(struct work_struct *work)
* We've got freeze protection passed with the transaction.
* Tell lockdep about it.
*/
- rwsem_acquire_read(
- &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
- 0, 1, _THIS_IP_);
+ if (ac->newtrans->type < TRANS_JOIN_NOLOCK)
+ rwsem_acquire_read(
+ &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
+ 0, 1, _THIS_IP_);
current->journal_info = ac->newtrans;
@@ -1349,8 +1350,10 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
* Tell lockdep we've released the freeze rwsem, since the
* async commit thread will be the one to unlock it.
*/
- rwsem_release(&root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
- 1, _THIS_IP_);
+ if (trans->type < TRANS_JOIN_NOLOCK)
+ rwsem_release(
+ &root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
+ 1, _THIS_IP_);
schedule_delayed_work(&ac->work, 0);
--
1.7.11.7
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 3/9] Btrfs: fix wrong return value of btrfs_wait_for_commit()
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 ` Miao Xie
2012-11-26 8:43 ` [PATCH 4/9] Btrfs: get write access when setting the default subvolume Miao Xie
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2012-11-26 8:42 UTC (permalink / raw)
To: Linux Btrfs
If the id of the existed transaction is more than the one we specified, it
means the specified transaction was commited, so we should return 0, not
EINVAL.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/transaction.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 350e9c4..788e079 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -461,28 +461,31 @@ static noinline void wait_for_commit(struct btrfs_root *root,
int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
{
struct btrfs_transaction *cur_trans = NULL, *t;
- int ret;
+ int ret = 0;
- ret = 0;
if (transid) {
if (transid <= root->fs_info->last_trans_committed)
goto out;
+ ret = -EINVAL;
/* find specified transaction */
spin_lock(&root->fs_info->trans_lock);
list_for_each_entry(t, &root->fs_info->trans_list, list) {
if (t->transid == transid) {
cur_trans = t;
atomic_inc(&cur_trans->use_count);
+ ret = 0;
break;
}
- if (t->transid > transid)
+ if (t->transid > transid) {
+ ret = 0;
break;
+ }
}
spin_unlock(&root->fs_info->trans_lock);
- ret = -EINVAL;
+ /* The specified transaction doesn't exist */
if (!cur_trans)
- goto out; /* bad transid */
+ goto out;
} else {
/* find newest transaction that is committing | committed */
spin_lock(&root->fs_info->trans_lock);
@@ -502,9 +505,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
}
wait_for_commit(root, cur_trans);
-
put_transaction(cur_trans);
- ret = 0;
out:
return ret;
}
--
1.7.11.7
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 4/9] Btrfs: get write access when setting the default subvolume
2012-11-26 8:39 [PATCH 0/9] random fix for btrfs_ioctl() Miao Xie
` (2 preceding siblings ...)
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 ` Miao Xie
2012-11-26 8:43 ` [PATCH 5/9] Btrfs: get write access when doing resize fs Miao Xie
` (4 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2012-11-26 8:43 UTC (permalink / raw)
To: Linux Btrfs
When wen want to set the default subvolume, we must get write access, or
we will change the R/O file system.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 40 ++++++++++++++++++++++++++++------------
1 file changed, 28 insertions(+), 12 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 5102747..7d0214b 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2823,12 +2823,19 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
struct btrfs_disk_key disk_key;
u64 objectid = 0;
u64 dir_id;
+ int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (copy_from_user(&objectid, argp, sizeof(objectid)))
- return -EFAULT;
+ ret = mnt_want_write_file(file);
+ if (ret)
+ return ret;
+
+ if (copy_from_user(&objectid, argp, sizeof(objectid))) {
+ ret = -EFAULT;
+ goto out;
+ }
if (!objectid)
objectid = root->root_key.objectid;
@@ -2838,21 +2845,28 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
location.offset = (u64)-1;
new_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
- if (IS_ERR(new_root))
- return PTR_ERR(new_root);
+ if (IS_ERR(new_root)) {
+ ret = PTR_ERR(new_root);
+ goto out;
+ }
- if (btrfs_root_refs(&new_root->root_item) == 0)
- return -ENOENT;
+ if (btrfs_root_refs(&new_root->root_item) == 0) {
+ ret = -ENOENT;
+ goto out;
+ }
path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
path->leave_spinning = 1;
trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
btrfs_free_path(path);
- return PTR_ERR(trans);
+ ret = PTR_ERR(trans);
+ goto out;
}
dir_id = btrfs_super_root_dir(root->fs_info->super_copy);
@@ -2863,7 +2877,8 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
btrfs_end_transaction(trans, root);
printk(KERN_ERR "Umm, you don't have the default dir item, "
"this isn't going to work\n");
- return -ENOENT;
+ ret = -ENOENT;
+ goto out;
}
btrfs_cpu_key_to_disk(&disk_key, &new_root->root_key);
@@ -2873,8 +2888,9 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
btrfs_set_fs_incompat(root->fs_info, DEFAULT_SUBVOL);
btrfs_end_transaction(trans, root);
-
- return 0;
+out:
+ mnt_drop_write_file(file);
+ return ret;
}
void btrfs_get_block_group_info(struct list_head *groups_list,
--
1.7.11.7
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 5/9] Btrfs: get write access when doing resize fs
2012-11-26 8:39 [PATCH 0/9] random fix for btrfs_ioctl() Miao Xie
` (3 preceding siblings ...)
2012-11-26 8:43 ` [PATCH 4/9] Btrfs: get write access when setting the default subvolume Miao Xie
@ 2012-11-26 8:43 ` Miao Xie
2012-11-26 8:44 ` [PATCH 6/9] Btrfs: get write access when removing a device Miao Xie
` (3 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2012-11-26 8:43 UTC (permalink / raw)
To: Linux Btrfs
Steps to reproduce:
# mkfs.btrfs <partition>
# mount -o ro <partition> <mnt0>
# mount -o ro <partition> <mnt1>
# mount -o remount,rw <mnt0>
# umount <mnt0>
# btrfs fi resize 10g <mnt1>
We re-sized a R/O filesystem. The reason is that 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 a full check.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 7d0214b..c4bcba5 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1293,12 +1293,13 @@ out_ra:
return ret;
}
-static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
+static noinline int btrfs_ioctl_resize(struct file *file,
void __user *arg)
{
u64 new_size;
u64 old_size;
u64 devid = 1;
+ struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_ioctl_vol_args *vol_args;
struct btrfs_trans_handle *trans;
struct btrfs_device *device = NULL;
@@ -1307,12 +1308,13 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
int ret = 0;
int mod = 0;
- if (root->fs_info->sb->s_flags & MS_RDONLY)
- return -EROFS;
-
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) {
printk(KERN_INFO "btrfs: balance in progress\n");
@@ -1415,6 +1417,7 @@ out_free:
kfree(vol_args);
out:
mutex_unlock(&root->fs_info->volume_mutex);
+ mnt_drop_write_file(file);
return ret;
}
@@ -3759,7 +3762,7 @@ long btrfs_ioctl(struct file *file, unsigned int
case BTRFS_IOC_DEFRAG_RANGE:
return btrfs_ioctl_defrag(file, argp);
case BTRFS_IOC_RESIZE:
- return btrfs_ioctl_resize(root, argp);
+ return btrfs_ioctl_resize(file, argp);
case BTRFS_IOC_ADD_DEV:
return btrfs_ioctl_add_dev(root, argp);
case BTRFS_IOC_RM_DEV:
--
1.7.11.7
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 6/9] Btrfs: get write access when removing a device
2012-11-26 8:39 [PATCH 0/9] random fix for btrfs_ioctl() Miao Xie
` (4 preceding siblings ...)
2012-11-26 8:43 ` [PATCH 5/9] Btrfs: get write access when doing resize fs Miao Xie
@ 2012-11-26 8:44 ` Miao Xie
2012-11-26 8:48 ` [PATCH 7/9] Btrfs: get write access for scrub Miao Xie
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2012-11-26 8:44 UTC (permalink / raw)
To: Linux Btrfs
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 delete <disk1> <mnt1>
We can remove a device from a R/O filesystem. The reason is that 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 a full check.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index c4bcba5..5921bb9 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2248,16 +2248,18 @@ out:
return ret;
}
-static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_rm_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;
- if (root->fs_info->sb->s_flags & MS_RDONLY)
- return -EROFS;
+ ret = mnt_want_write_file(file);
+ if (ret)
+ return ret;
mutex_lock(&root->fs_info->volume_mutex);
if (root->fs_info->balance_ctl) {
@@ -2278,6 +2280,7 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
kfree(vol_args);
out:
mutex_unlock(&root->fs_info->volume_mutex);
+ mnt_drop_write_file(file);
return ret;
}
@@ -3766,7 +3769,7 @@ long btrfs_ioctl(struct file *file, unsigned int
case BTRFS_IOC_ADD_DEV:
return btrfs_ioctl_add_dev(root, argp);
case BTRFS_IOC_RM_DEV:
- return btrfs_ioctl_rm_dev(root, argp);
+ return btrfs_ioctl_rm_dev(file, argp);
case BTRFS_IOC_FS_INFO:
return btrfs_ioctl_fs_info(root, argp);
case BTRFS_IOC_DEV_INFO:
--
1.7.11.7
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 7/9] Btrfs: get write access for scrub
2012-11-26 8:39 [PATCH 0/9] random fix for btrfs_ioctl() Miao Xie
` (5 preceding siblings ...)
2012-11-26 8:44 ` [PATCH 6/9] Btrfs: get write access when removing a device Miao Xie
@ 2012-11-26 8:48 ` Miao Xie
2012-11-26 8:50 ` [PATCH 8/9] Btrfs: get write access for qgroup operations Miao Xie
2012-11-26 8:51 ` [RFC PATCH 9/9] Btrfs: get write access for adding device Miao Xie
8 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2012-11-26 8:48 UTC (permalink / raw)
To: Linux Btrfs; +Cc: Jan Schmidt
We need get write access for scrub, or we will modify the R/O fs.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 5921bb9..a7afafa 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3103,10 +3103,11 @@ static noinline long btrfs_ioctl_wait_sync(struct btrfs_root *root,
return btrfs_wait_for_commit(root, transid);
}
-static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_scrub(struct file *file, void __user *arg)
{
- int ret;
+ struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_ioctl_scrub_args *sa;
+ int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -3115,12 +3116,21 @@ static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
if (IS_ERR(sa))
return PTR_ERR(sa);
+ if (!(sa->flags & BTRFS_SCRUB_READONLY)) {
+ ret = mnt_want_write_file(file);
+ if (ret)
+ goto out;
+ }
+
ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end,
&sa->progress, sa->flags & BTRFS_SCRUB_READONLY);
if (copy_to_user(arg, sa, sizeof(*sa)))
ret = -EFAULT;
+ if (!(sa->flags & BTRFS_SCRUB_READONLY))
+ mnt_drop_write_file(file);
+out:
kfree(sa);
return ret;
}
@@ -3802,7 +3812,7 @@ long btrfs_ioctl(struct file *file, unsigned int
case BTRFS_IOC_WAIT_SYNC:
return btrfs_ioctl_wait_sync(root, argp);
case BTRFS_IOC_SCRUB:
- return btrfs_ioctl_scrub(root, argp);
+ return btrfs_ioctl_scrub(file, argp);
case BTRFS_IOC_SCRUB_CANCEL:
return btrfs_ioctl_scrub_cancel(root, argp);
case BTRFS_IOC_SCRUB_PROGRESS:
--
1.7.11.7
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 8/9] Btrfs: get write access for qgroup operations
2012-11-26 8:39 [PATCH 0/9] random fix for btrfs_ioctl() Miao Xie
` (6 preceding siblings ...)
2012-11-26 8:48 ` [PATCH 7/9] Btrfs: get write access for scrub Miao Xie
@ 2012-11-26 8:50 ` Miao Xie
2012-11-26 8:51 ` [RFC PATCH 9/9] Btrfs: get write access for adding device Miao Xie
8 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2012-11-26 8:50 UTC (permalink / raw)
To: Linux Btrfs; +Cc: Arne Jansen
We need get write access for qgroup operations, or we will modify the R/O fs.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 73 +++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 48 insertions(+), 25 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index a7afafa..e6525d1 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3481,8 +3481,9 @@ out:
return ret;
}
-static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg)
{
+ struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_ioctl_quota_ctl_args *sa;
struct btrfs_trans_handle *trans = NULL;
int ret;
@@ -3491,12 +3492,15 @@ static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (root->fs_info->sb->s_flags & MS_RDONLY)
- return -EROFS;
+ ret = mnt_want_write_file(file);
+ if (ret)
+ return ret;
sa = memdup_user(arg, sizeof(*sa));
- if (IS_ERR(sa))
- return PTR_ERR(sa);
+ if (IS_ERR(sa)) {
+ ret = PTR_ERR(sa);
+ goto drop_write;
+ }
if (sa->cmd != BTRFS_QUOTA_CTL_RESCAN) {
trans = btrfs_start_transaction(root, 2);
@@ -3529,14 +3533,16 @@ static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg)
if (err && !ret)
ret = err;
}
-
out:
kfree(sa);
+drop_write:
+ mnt_drop_write_file(file);
return ret;
}
-static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
{
+ struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_ioctl_qgroup_assign_args *sa;
struct btrfs_trans_handle *trans;
int ret;
@@ -3545,12 +3551,15 @@ static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (root->fs_info->sb->s_flags & MS_RDONLY)
- return -EROFS;
+ ret = mnt_want_write_file(file);
+ if (ret)
+ return ret;
sa = memdup_user(arg, sizeof(*sa));
- if (IS_ERR(sa))
- return PTR_ERR(sa);
+ if (IS_ERR(sa)) {
+ ret = PTR_ERR(sa);
+ goto drop_write;
+ }
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
@@ -3573,11 +3582,14 @@ static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg)
out:
kfree(sa);
+drop_write:
+ mnt_drop_write_file(file);
return ret;
}
-static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg)
{
+ struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_ioctl_qgroup_create_args *sa;
struct btrfs_trans_handle *trans;
int ret;
@@ -3586,12 +3598,15 @@ static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (root->fs_info->sb->s_flags & MS_RDONLY)
- return -EROFS;
+ ret = mnt_want_write_file(file);
+ if (ret)
+ return ret;
sa = memdup_user(arg, sizeof(*sa));
- if (IS_ERR(sa))
- return PTR_ERR(sa);
+ if (IS_ERR(sa)) {
+ ret = PTR_ERR(sa);
+ goto drop_write;
+ }
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
@@ -3613,11 +3628,14 @@ static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg)
out:
kfree(sa);
+drop_write:
+ mnt_drop_write_file(file);
return ret;
}
-static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg)
{
+ struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_ioctl_qgroup_limit_args *sa;
struct btrfs_trans_handle *trans;
int ret;
@@ -3627,12 +3645,15 @@ static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (root->fs_info->sb->s_flags & MS_RDONLY)
- return -EROFS;
+ ret = mnt_want_write_file(file);
+ if (ret)
+ return ret;
sa = memdup_user(arg, sizeof(*sa));
- if (IS_ERR(sa))
- return PTR_ERR(sa);
+ if (IS_ERR(sa)) {
+ ret = PTR_ERR(sa);
+ goto drop_write;
+ }
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
@@ -3655,6 +3676,8 @@ static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg)
out:
kfree(sa);
+drop_write:
+ mnt_drop_write_file(file);
return ret;
}
@@ -3830,13 +3853,13 @@ long btrfs_ioctl(struct file *file, unsigned int
case BTRFS_IOC_GET_DEV_STATS:
return btrfs_ioctl_get_dev_stats(root, argp);
case BTRFS_IOC_QUOTA_CTL:
- return btrfs_ioctl_quota_ctl(root, argp);
+ return btrfs_ioctl_quota_ctl(file, argp);
case BTRFS_IOC_QGROUP_ASSIGN:
- return btrfs_ioctl_qgroup_assign(root, argp);
+ return btrfs_ioctl_qgroup_assign(file, argp);
case BTRFS_IOC_QGROUP_CREATE:
- return btrfs_ioctl_qgroup_create(root, argp);
+ return btrfs_ioctl_qgroup_create(file, argp);
case BTRFS_IOC_QGROUP_LIMIT:
- return btrfs_ioctl_qgroup_limit(root, argp);
+ return btrfs_ioctl_qgroup_limit(file, argp);
}
return -ENOTTY;
--
1.7.11.7
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC PATCH 9/9] Btrfs: get write access for adding device
2012-11-26 8:39 [PATCH 0/9] random fix for btrfs_ioctl() Miao Xie
` (7 preceding siblings ...)
2012-11-26 8:50 ` [PATCH 8/9] Btrfs: get write access for qgroup operations Miao Xie
@ 2012-11-26 8:51 ` Miao Xie
2012-12-12 2:52 ` Miao Xie
8 siblings, 1 reply; 11+ messages in thread
From: Miao Xie @ 2012-11-26 8:51 UTC (permalink / raw)
To: Linux Btrfs
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
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [RFC PATCH 9/9] Btrfs: get write access for adding device
2012-11-26 8:51 ` [RFC PATCH 9/9] Btrfs: get write access for adding device Miao Xie
@ 2012-12-12 2:52 ` Miao Xie
0 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2012-12-12 2:52 UTC (permalink / raw)
To: Linux Btrfs
Any comment about this patch?
On mon, 26 Nov 2012 16:51:36 +0800, Miao Xie wrote:
> 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);
>
^ permalink raw reply [flat|nested] 11+ messages in thread