Commit 68a507a2 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: fix truncate with ATTR_MODE

After the v5.12 rebase, we started oopsing when truncate was passed
ATTR_MODE, due to not passing mnt_userns to setattr_copy(). This
refactors things so that truncate/extend finish by using
bch2_setattr_nonsize(), which solves the problem.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent 8c3f6da9
...@@ -2252,11 +2252,11 @@ static int bch2_truncate_page(struct bch_inode_info *inode, loff_t from) ...@@ -2252,11 +2252,11 @@ static int bch2_truncate_page(struct bch_inode_info *inode, loff_t from)
from, round_up(from, PAGE_SIZE)); from, round_up(from, PAGE_SIZE));
} }
static int bch2_extend(struct bch_inode_info *inode, static int bch2_extend(struct mnt_idmap *idmap,
struct bch_inode_info *inode,
struct bch_inode_unpacked *inode_u, struct bch_inode_unpacked *inode_u,
struct iattr *iattr) struct iattr *iattr)
{ {
struct bch_fs *c = inode->v.i_sb->s_fs_info;
struct address_space *mapping = inode->v.i_mapping; struct address_space *mapping = inode->v.i_mapping;
int ret; int ret;
...@@ -2270,25 +2270,15 @@ static int bch2_extend(struct bch_inode_info *inode, ...@@ -2270,25 +2270,15 @@ static int bch2_extend(struct bch_inode_info *inode,
return ret; return ret;
truncate_setsize(&inode->v, iattr->ia_size); truncate_setsize(&inode->v, iattr->ia_size);
/* ATTR_MODE will never be set here, ns argument isn't needed: */
setattr_copy(NULL, &inode->v, iattr);
mutex_lock(&inode->ei_update_lock);
ret = bch2_write_inode_size(c, inode, inode->v.i_size,
ATTR_MTIME|ATTR_CTIME);
mutex_unlock(&inode->ei_update_lock);
return ret; return bch2_setattr_nonsize(idmap, inode, iattr);
} }
static int bch2_truncate_finish_fn(struct bch_inode_info *inode, static int bch2_truncate_finish_fn(struct bch_inode_info *inode,
struct bch_inode_unpacked *bi, struct bch_inode_unpacked *bi,
void *p) void *p)
{ {
struct bch_fs *c = inode->v.i_sb->s_fs_info;
bi->bi_flags &= ~BCH_INODE_I_SIZE_DIRTY; bi->bi_flags &= ~BCH_INODE_I_SIZE_DIRTY;
bi->bi_mtime = bi->bi_ctime = bch2_current_time(c);
return 0; return 0;
} }
...@@ -2302,7 +2292,8 @@ static int bch2_truncate_start_fn(struct bch_inode_info *inode, ...@@ -2302,7 +2292,8 @@ static int bch2_truncate_start_fn(struct bch_inode_info *inode,
return 0; return 0;
} }
int bch2_truncate(struct bch_inode_info *inode, struct iattr *iattr) int bch2_truncate(struct mnt_idmap *idmap,
struct bch_inode_info *inode, struct iattr *iattr)
{ {
struct bch_fs *c = inode->v.i_sb->s_fs_info; struct bch_fs *c = inode->v.i_sb->s_fs_info;
struct address_space *mapping = inode->v.i_mapping; struct address_space *mapping = inode->v.i_mapping;
...@@ -2313,6 +2304,18 @@ int bch2_truncate(struct bch_inode_info *inode, struct iattr *iattr) ...@@ -2313,6 +2304,18 @@ int bch2_truncate(struct bch_inode_info *inode, struct iattr *iattr)
s64 i_sectors_delta = 0; s64 i_sectors_delta = 0;
int ret = 0; int ret = 0;
/*
* Don't update timestamps if we're not doing anything:
*/
if (iattr->ia_size == inode->v.i_size)
return 0;
if (!(iattr->ia_valid & ATTR_MTIME))
ktime_get_coarse_real_ts64(&iattr->ia_mtime);
if (!(iattr->ia_valid & ATTR_CTIME))
ktime_get_coarse_real_ts64(&iattr->ia_ctime);
iattr->ia_valid |= ATTR_MTIME|ATTR_CTIME;
inode_dio_wait(&inode->v); inode_dio_wait(&inode->v);
bch2_pagecache_block_get(&inode->ei_pagecache_lock); bch2_pagecache_block_get(&inode->ei_pagecache_lock);
...@@ -2342,10 +2345,12 @@ int bch2_truncate(struct bch_inode_info *inode, struct iattr *iattr) ...@@ -2342,10 +2345,12 @@ int bch2_truncate(struct bch_inode_info *inode, struct iattr *iattr)
inode->v.i_size < inode_u.bi_size); inode->v.i_size < inode_u.bi_size);
if (iattr->ia_size > inode->v.i_size) { if (iattr->ia_size > inode->v.i_size) {
ret = bch2_extend(inode, &inode_u, iattr); ret = bch2_extend(idmap, inode, &inode_u, iattr);
goto err; goto err;
} }
iattr->ia_valid &= ~ATTR_SIZE;
ret = bch2_truncate_page(inode, iattr->ia_size); ret = bch2_truncate_page(inode, iattr->ia_size);
if (unlikely(ret)) if (unlikely(ret))
goto err; goto err;
...@@ -2389,13 +2394,11 @@ int bch2_truncate(struct bch_inode_info *inode, struct iattr *iattr) ...@@ -2389,13 +2394,11 @@ int bch2_truncate(struct bch_inode_info *inode, struct iattr *iattr)
if (unlikely(ret)) if (unlikely(ret))
goto err; goto err;
/* ATTR_MODE will never be set here, ns argument isn't needed: */
setattr_copy(NULL, &inode->v, iattr);
mutex_lock(&inode->ei_update_lock); mutex_lock(&inode->ei_update_lock);
ret = bch2_write_inode(c, inode, bch2_truncate_finish_fn, NULL, ret = bch2_write_inode(c, inode, bch2_truncate_finish_fn, NULL, 0);
ATTR_MTIME|ATTR_CTIME);
mutex_unlock(&inode->ei_update_lock); mutex_unlock(&inode->ei_update_lock);
ret = bch2_setattr_nonsize(idmap, inode, iattr);
err: err:
bch2_pagecache_block_put(&inode->ei_pagecache_lock); bch2_pagecache_block_put(&inode->ei_pagecache_lock);
return ret; return ret;
......
...@@ -31,7 +31,8 @@ ssize_t bch2_write_iter(struct kiocb *, struct iov_iter *); ...@@ -31,7 +31,8 @@ ssize_t bch2_write_iter(struct kiocb *, struct iov_iter *);
int bch2_fsync(struct file *, loff_t, loff_t, int); int bch2_fsync(struct file *, loff_t, loff_t, int);
int bch2_truncate(struct bch_inode_info *, struct iattr *); int bch2_truncate(struct mnt_idmap *,
struct bch_inode_info *, struct iattr *);
long bch2_fallocate_dispatch(struct file *, int, loff_t, loff_t); long bch2_fallocate_dispatch(struct file *, int, loff_t, loff_t);
loff_t bch2_remap_file_range(struct file *, loff_t, struct file *, loff_t bch2_remap_file_range(struct file *, loff_t, struct file *,
......
...@@ -662,6 +662,9 @@ static void bch2_setattr_copy(struct mnt_idmap *idmap, ...@@ -662,6 +662,9 @@ static void bch2_setattr_copy(struct mnt_idmap *idmap,
if (ia_valid & ATTR_GID) if (ia_valid & ATTR_GID)
bi->bi_gid = from_kgid(i_user_ns(&inode->v), attr->ia_gid); bi->bi_gid = from_kgid(i_user_ns(&inode->v), attr->ia_gid);
if (ia_valid & ATTR_SIZE)
bi->bi_size = attr->ia_size;
if (ia_valid & ATTR_ATIME) if (ia_valid & ATTR_ATIME)
bi->bi_atime = timespec_to_bch2_time(c, attr->ia_atime); bi->bi_atime = timespec_to_bch2_time(c, attr->ia_atime);
if (ia_valid & ATTR_MTIME) if (ia_valid & ATTR_MTIME)
...@@ -682,9 +685,9 @@ static void bch2_setattr_copy(struct mnt_idmap *idmap, ...@@ -682,9 +685,9 @@ static void bch2_setattr_copy(struct mnt_idmap *idmap,
} }
} }
static int bch2_setattr_nonsize(struct mnt_idmap *idmap, int bch2_setattr_nonsize(struct mnt_idmap *idmap,
struct bch_inode_info *inode, struct bch_inode_info *inode,
struct iattr *attr) struct iattr *attr)
{ {
struct bch_fs *c = inode->v.i_sb->s_fs_info; struct bch_fs *c = inode->v.i_sb->s_fs_info;
struct bch_qid qid; struct bch_qid qid;
...@@ -808,7 +811,7 @@ static int bch2_setattr(struct mnt_idmap *idmap, ...@@ -808,7 +811,7 @@ static int bch2_setattr(struct mnt_idmap *idmap,
return ret; return ret;
return iattr->ia_valid & ATTR_SIZE return iattr->ia_valid & ATTR_SIZE
? bch2_truncate(inode, iattr) ? bch2_truncate(idmap, inode, iattr)
: bch2_setattr_nonsize(idmap, inode, iattr); : bch2_setattr_nonsize(idmap, inode, iattr);
} }
......
...@@ -166,6 +166,10 @@ void bch2_inode_update_after_write(struct bch_fs *, ...@@ -166,6 +166,10 @@ void bch2_inode_update_after_write(struct bch_fs *,
int __must_check bch2_write_inode(struct bch_fs *, struct bch_inode_info *, int __must_check bch2_write_inode(struct bch_fs *, struct bch_inode_info *,
inode_set_fn, void *, unsigned); inode_set_fn, void *, unsigned);
int bch2_setattr_nonsize(struct mnt_idmap *,
struct bch_inode_info *,
struct iattr *);
void bch2_vfs_exit(void); void bch2_vfs_exit(void);
int bch2_vfs_init(void); int bch2_vfs_init(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment