Skip to content

Commit 0d72ab3

Browse files
author
Kent Overstreet
committed
bcachefs: make RO snapshots actually RO
Add checks to all the VFS paths for "are we in a RO snapshot?". Note - we don't check this when setting inode options via our xattr interface, since those generally only affect data placement, not contents of data. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev> Reported-by: "Carl E. Thompson" <list-bcachefs@carlthompson.net>
1 parent 84f1638 commit 0d72ab3

File tree

6 files changed

+63
-14
lines changed

6 files changed

+63
-14
lines changed

fs/bcachefs/acl.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,8 @@ int bch2_set_acl(struct mnt_idmap *idmap,
366366
bch2_trans_begin(trans);
367367
acl = _acl;
368368

369-
ret = bch2_inode_peek(trans, &inode_iter, &inode_u, inode_inum(inode),
369+
ret = bch2_subvol_is_ro_trans(trans, inode->ei_subvol) ?:
370+
bch2_inode_peek(trans, &inode_iter, &inode_u, inode_inum(inode),
370371
BTREE_ITER_INTENT);
371372
if (ret)
372373
goto btree_err;

fs/bcachefs/fs-ioctl.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ static int bch2_ioc_setflags(struct bch_fs *c,
100100
}
101101

102102
mutex_lock(&inode->ei_update_lock);
103-
ret = bch2_write_inode(c, inode, bch2_inode_flags_set, &s,
103+
ret = bch2_subvol_is_ro(c, inode->ei_subvol) ?:
104+
bch2_write_inode(c, inode, bch2_inode_flags_set, &s,
104105
ATTR_CTIME);
105106
mutex_unlock(&inode->ei_update_lock);
106107

@@ -183,13 +184,10 @@ static int bch2_ioc_fssetxattr(struct bch_fs *c,
183184
}
184185

185186
mutex_lock(&inode->ei_update_lock);
186-
ret = bch2_set_projid(c, inode, fa.fsx_projid);
187-
if (ret)
188-
goto err_unlock;
189-
190-
ret = bch2_write_inode(c, inode, fssetxattr_inode_update_fn, &s,
187+
ret = bch2_subvol_is_ro(c, inode->ei_subvol) ?:
188+
bch2_set_projid(c, inode, fa.fsx_projid) ?:
189+
bch2_write_inode(c, inode, fssetxattr_inode_update_fn, &s,
191190
ATTR_CTIME);
192-
err_unlock:
193191
mutex_unlock(&inode->ei_update_lock);
194192
err:
195193
inode_unlock(&inode->v);

fs/bcachefs/fs.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@ __bch2_create(struct mnt_idmap *idmap,
258258
retry:
259259
bch2_trans_begin(trans);
260260

261-
ret = bch2_create_trans(trans,
261+
ret = bch2_subvol_is_ro_trans(trans, dir->ei_subvol) ?:
262+
bch2_create_trans(trans,
262263
inode_inum(dir), &dir_u, &inode_u,
263264
!(flags & BCH_CREATE_TMPFILE)
264265
? &dentry->d_name : NULL,
@@ -430,7 +431,9 @@ static int bch2_link(struct dentry *old_dentry, struct inode *vdir,
430431

431432
lockdep_assert_held(&inode->v.i_rwsem);
432433

433-
ret = __bch2_link(c, inode, dir, dentry);
434+
ret = bch2_subvol_is_ro(c, dir->ei_subvol) ?:
435+
bch2_subvol_is_ro(c, inode->ei_subvol) ?:
436+
__bch2_link(c, inode, dir, dentry);
434437
if (unlikely(ret))
435438
return ret;
436439

@@ -481,7 +484,11 @@ int __bch2_unlink(struct inode *vdir, struct dentry *dentry,
481484

482485
static int bch2_unlink(struct inode *vdir, struct dentry *dentry)
483486
{
484-
return __bch2_unlink(vdir, dentry, false);
487+
struct bch_inode_info *dir= to_bch_ei(vdir);
488+
struct bch_fs *c = dir->v.i_sb->s_fs_info;
489+
490+
return bch2_subvol_is_ro(c, dir->ei_subvol) ?:
491+
__bch2_unlink(vdir, dentry, false);
485492
}
486493

487494
static int bch2_symlink(struct mnt_idmap *idmap,
@@ -562,6 +569,11 @@ static int bch2_rename2(struct mnt_idmap *idmap,
562569
src_inode,
563570
dst_inode);
564571

572+
ret = bch2_subvol_is_ro_trans(trans, src_dir->ei_subvol) ?:
573+
bch2_subvol_is_ro_trans(trans, dst_dir->ei_subvol);
574+
if (ret)
575+
goto err;
576+
565577
if (inode_attr_changing(dst_dir, src_inode, Inode_opt_project)) {
566578
ret = bch2_fs_quota_transfer(c, src_inode,
567579
dst_dir->ei_qid,
@@ -783,11 +795,13 @@ static int bch2_setattr(struct mnt_idmap *idmap,
783795
struct dentry *dentry, struct iattr *iattr)
784796
{
785797
struct bch_inode_info *inode = to_bch_ei(dentry->d_inode);
798+
struct bch_fs *c = inode->v.i_sb->s_fs_info;
786799
int ret;
787800

788801
lockdep_assert_held(&inode->v.i_rwsem);
789802

790-
ret = setattr_prepare(idmap, dentry, iattr);
803+
ret = bch2_subvol_is_ro(c, inode->ei_subvol) ?:
804+
setattr_prepare(idmap, dentry, iattr);
791805
if (ret)
792806
return ret;
793807

@@ -1010,12 +1024,26 @@ static int bch2_vfs_readdir(struct file *file, struct dir_context *ctx)
10101024
return bch2_err_class(ret);
10111025
}
10121026

1027+
static int bch2_open(struct inode *vinode, struct file *file)
1028+
{
1029+
if (file->f_flags & (O_WRONLY|O_RDWR)) {
1030+
struct bch_inode_info *inode = to_bch_ei(vinode);
1031+
struct bch_fs *c = inode->v.i_sb->s_fs_info;
1032+
1033+
int ret = bch2_subvol_is_ro(c, inode->ei_subvol);
1034+
if (ret)
1035+
return ret;
1036+
}
1037+
1038+
return generic_file_open(vinode, file);
1039+
}
1040+
10131041
static const struct file_operations bch_file_operations = {
1042+
.open = bch2_open,
10141043
.llseek = bch2_llseek,
10151044
.read_iter = bch2_read_iter,
10161045
.write_iter = bch2_write_iter,
10171046
.mmap = bch2_mmap,
1018-
.open = generic_file_open,
10191047
.fsync = bch2_fsync,
10201048
.splice_read = filemap_splice_read,
10211049
.splice_write = iter_file_splice_write,

fs/bcachefs/subvolume.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,24 @@ int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol,
146146
return bch2_subvolume_get_inlined(trans, subvol, inconsistent_if_not_found, iter_flags, s);
147147
}
148148

149+
int bch2_subvol_is_ro_trans(struct btree_trans *trans, u32 subvol)
150+
{
151+
struct bch_subvolume s;
152+
int ret = bch2_subvolume_get_inlined(trans, subvol, true, 0, &s);
153+
if (ret)
154+
return ret;
155+
156+
if (BCH_SUBVOLUME_RO(&s))
157+
return -EROFS;
158+
return 0;
159+
}
160+
161+
int bch2_subvol_is_ro(struct bch_fs *c, u32 subvol)
162+
{
163+
return bch2_trans_do(c, NULL, NULL, 0,
164+
bch2_subvol_is_ro_trans(trans, subvol));
165+
}
166+
149167
int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot,
150168
struct bch_subvolume *subvol)
151169
{

fs/bcachefs/subvolume.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ int bch2_subvolume_get(struct btree_trans *, unsigned,
2323
bool, int, struct bch_subvolume *);
2424
int bch2_subvolume_get_snapshot(struct btree_trans *, u32, u32 *);
2525

26+
int bch2_subvol_is_ro_trans(struct btree_trans *, u32);
27+
int bch2_subvol_is_ro(struct bch_fs *, u32);
28+
2629
int bch2_delete_dead_snapshots(struct bch_fs *);
2730
void bch2_delete_dead_snapshots_async(struct bch_fs *);
2831

fs/bcachefs/xattr.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ int bch2_xattr_set(struct btree_trans *trans, subvol_inum inum,
176176
struct btree_iter inode_iter = { NULL };
177177
int ret;
178178

179-
ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum, BTREE_ITER_INTENT);
179+
ret = bch2_subvol_is_ro_trans(trans, inum.subvol) ?:
180+
bch2_inode_peek(trans, &inode_iter, inode_u, inum, BTREE_ITER_INTENT);
180181
if (ret)
181182
return ret;
182183

0 commit comments

Comments
 (0)