Skip to content

Commit 94628ad

Browse files
ltragerkdave
authored andcommitted
btrfs: copy dir permission and time when creating a stub subvolume
btrfs supports creating nested subvolumes however snapshots are not recursive. When a snapshot is taken of a volume which contains a subvolume the subvolume is replaced with a stub subvolume which has the same name and uses inode number 2[1]. The stub subvolume kept the directory name but did not set the time or permissions of the stub subvolume. This resulted in all time information being the current time and ownership defaulting to root. When subvolumes and snapshots are created using unshare this results in a snapshot directory the user created but has no permissions for. Test case: [vmuser@archvm ~]# sudo -i [root@archvm ~]# mkdir -p /mnt/btrfs/test [root@archvm ~]# chown vmuser:users /mnt/btrfs/test/ [root@archvm ~]# exit logout [vmuser@archvm ~]$ cd /mnt/btrfs/test [vmuser@archvm test]$ unshare --user --keep-caps --map-auto --map-root-user [root@archvm test]# btrfs subvolume create subvolume Create subvolume './subvolume' [root@archvm test]# btrfs subvolume create subvolume/subsubvolume Create subvolume 'subvolume/subsubvolume' [root@archvm test]# btrfs subvolume snapshot subvolume snapshot Create a snapshot of 'subvolume' in './snapshot' [root@archvm test]# exit logout [vmuser@archvm test]$ tree -ug [vmuser users ] . ├── [vmuser users ] snapshot │   └── [vmuser users ] subsubvolume <-- Without patch perm is root:root └── [vmuser users ] subvolume └── [vmuser users ] subsubvolume 5 directories, 0 files [1] https://btrfs.readthedocs.io/en/latest/btrfs-subvolume.html#nested-subvolumes Signed-off-by: Lee Trager <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 6b604c9 commit 94628ad

File tree

1 file changed

+7
-5
lines changed

1 file changed

+7
-5
lines changed

fs/btrfs/inode.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5585,11 +5585,11 @@ struct inode *btrfs_iget(struct super_block *s, u64 ino, struct btrfs_root *root
55855585
return btrfs_iget_path(s, ino, root, NULL);
55865586
}
55875587

5588-
static struct inode *new_simple_dir(struct super_block *s,
5588+
static struct inode *new_simple_dir(struct inode *dir,
55895589
struct btrfs_key *key,
55905590
struct btrfs_root *root)
55915591
{
5592-
struct inode *inode = new_inode(s);
5592+
struct inode *inode = new_inode(dir->i_sb);
55935593

55945594
if (!inode)
55955595
return ERR_PTR(-ENOMEM);
@@ -5608,9 +5608,11 @@ static struct inode *new_simple_dir(struct super_block *s,
56085608
inode->i_fop = &simple_dir_operations;
56095609
inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
56105610
inode->i_mtime = current_time(inode);
5611-
inode->i_atime = inode->i_mtime;
5612-
inode->i_ctime = inode->i_mtime;
5611+
inode->i_atime = dir->i_atime;
5612+
inode->i_ctime = dir->i_ctime;
56135613
BTRFS_I(inode)->i_otime = inode->i_mtime;
5614+
inode->i_uid = dir->i_uid;
5615+
inode->i_gid = dir->i_gid;
56145616

56155617
return inode;
56165618
}
@@ -5669,7 +5671,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
56695671
if (ret != -ENOENT)
56705672
inode = ERR_PTR(ret);
56715673
else
5672-
inode = new_simple_dir(dir->i_sb, &location, root);
5674+
inode = new_simple_dir(dir, &location, root);
56735675
} else {
56745676
inode = btrfs_iget(dir->i_sb, location.objectid, sub_root);
56755677
btrfs_put_root(sub_root);

0 commit comments

Comments
 (0)