diff options
author | David Sterba <dsterba@suse.cz> | 2011-09-29 07:11:33 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.cz> | 2011-10-24 08:43:25 -0400 |
commit | f9d9ef62cd3ecbd6cbb7957a253c1e81f69d5586 (patch) | |
tree | 34e9cf9c3c5f2332e2e59500de8c5c1ff4065c7b /fs/btrfs | |
parent | 20bcd64934e4eb8f3f90a0dca54fb0ac2edd7795 (diff) |
btrfs: do not allow mounting non-subvolumes via subvol option
There's a missing test whether the path passed to subvol=path option
during mount is a real subvolume, allowing any directory located in
default subovlume to be passed and accepted for mount.
(current btrfs progs prevent this early)
$ btrfs subvol snapshot . p1-snap
ERROR: '.' is not a subvolume
(with "is subvolume?" test bypassed)
$ btrfs subvol snapshot . p1-snap
Create a snapshot of '.' in './p1-snap'
$ btrfs subvol list -p .
ID 258 parent 5 top level 5 path subvol
ID 259 parent 5 top level 5 path subvol1
ID 260 parent 5 top level 5 path default-subvol1
ID 262 parent 5 top level 5 path p1/p1-snapshot
ID 263 parent 259 top level 5 path subvol1/subvol1-snap
The problem I see is that this makes a false impression of snapshotting the
given subvolume but in fact snapshots the default one: a user expects outcome
like ID 263 but in fact gets ID 262 .
This patch makes mount fail with EINVAL with a message in syslog.
Signed-off-by: David Sterba <dsterba@suse.cz>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/super.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 29eecbb6ec3..5429b1fa0bf 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -741,6 +741,16 @@ static int btrfs_set_super(struct super_block *s, void *data) | |||
741 | } | 741 | } |
742 | 742 | ||
743 | /* | 743 | /* |
744 | * subvolumes are identified by ino 256 | ||
745 | */ | ||
746 | static inline int is_subvolume_inode(struct inode *inode) | ||
747 | { | ||
748 | if (inode && inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) | ||
749 | return 1; | ||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | /* | ||
744 | * This will strip out the subvol=%s argument for an argument string and add | 754 | * This will strip out the subvol=%s argument for an argument string and add |
745 | * subvolid=0 to make sure we get the actual tree root for path walking to the | 755 | * subvolid=0 to make sure we get the actual tree root for path walking to the |
746 | * subvol we want. | 756 | * subvol we want. |
@@ -843,6 +853,15 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags, | |||
843 | if (error) | 853 | if (error) |
844 | return ERR_PTR(error); | 854 | return ERR_PTR(error); |
845 | 855 | ||
856 | if (!is_subvolume_inode(path.dentry->d_inode)) { | ||
857 | path_put(&path); | ||
858 | mntput(mnt); | ||
859 | error = -EINVAL; | ||
860 | printk(KERN_ERR "btrfs: '%s' is not a valid subvolume\n", | ||
861 | subvol_name); | ||
862 | return ERR_PTR(-EINVAL); | ||
863 | } | ||
864 | |||
846 | /* Get a ref to the sb and the dentry we found and return it */ | 865 | /* Get a ref to the sb and the dentry we found and return it */ |
847 | s = path.mnt->mnt_sb; | 866 | s = path.mnt->mnt_sb; |
848 | atomic_inc(&s->s_active); | 867 | atomic_inc(&s->s_active); |