Re: [PATCH v2 18/21] backing-inode: add backing_inode_setattr()
Amir Goldstein <[email protected]> Sun, 17 May 2026 00:47:22 +0200
| Newsgroups | org.kernel.vger.linux-unionfs,dev.linux.lists.fuse-devel |
|---|---|
| Message-ID | <CAOQ4uxjzPRQTNqasMrNELKOpvSBmuFGxmfygQbx5osuCwWVjdA@mail.gmail.com> |
On Sat, May 16, 2026 at 2:53 AM Joanne Koong <[email protected]> wrote: > > Move logic in ovl_setattr() to a generic backing_inode_setattr() function > in fs/backing-inode.c, which other filesystems that use backing inodes > (eg fuse passthrough) will use. > > Signed-off-by: Joanne Koong <[email protected]> Wow this code brings back memories that I tried hard to forget :) I hope that fuse passthrough can reap the benefits of all the bugs and fixes in ovl_setattr()... Reviewed-by: Amir Goldstein <[email protected]> > --- > fs/backing-inode.c | 54 ++++++++++++++++++++++++++++ > fs/overlayfs/inode.c | 66 ++++++++++------------------------- > include/linux/backing-inode.h | 4 +++ > 3 files changed, 76 insertions(+), 48 deletions(-) > > diff --git a/fs/backing-inode.c b/fs/backing-inode.c > index 474770a1fa9d..e72f278789d8 100644 > --- a/fs/backing-inode.c > +++ b/fs/backing-inode.c > @@ -41,3 +41,57 @@ void backing_inode_copyattr(struct inode *inode, > } > EXPORT_SYMBOL_GPL(backing_inode_copyattr); > > +int backing_inode_setattr(struct dentry *dentry, > + const struct path *backing_path, > + struct iattr *attr, const struct cred *cred) > +{ > + struct dentry *backing_dentry = backing_path->dentry; > + struct inode *winode = NULL; > + int err; > + > + if (attr->ia_valid & ATTR_SIZE) { > + winode = d_inode(backing_dentry); > + err = get_write_access(winode); > + if (err) > + return err; > + } > + > + /* > + * Clear ATTR_MODE to avoid BUG_ON in notify_change(), which does not > + * allow ATTR_MODE together with ATTR_KILL_SUID/SGID (the first > + * notify_change() converted ATTR_KILL_SUID/SGID into ATTR_MODE using > + * @dentry's inode mode). > + * > + * This also ensures notify_change() recomputes the mode from the > + * backing inode's current mode, instead of a potentially stale value > + * from @dentry's inode. > + */ > + if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) > + attr->ia_valid &= ~ATTR_MODE; > + > + /* > + * The filesystem's file is not meaningful to the backing filesystem. > + * Clear ATTR_FILE so the backing filesystem does not try to use it. > + */ > + attr->ia_valid &= ~ATTR_FILE; > + > + err = mnt_want_write(backing_path->mnt); > + if (err) > + goto out_put_write; > + > + inode_lock(backing_dentry->d_inode); > + scoped_with_creds(cred) > + err = notify_change(mnt_idmap(backing_path->mnt), > + backing_dentry, attr, NULL); > + if (!err) > + backing_inode_copyattr(dentry->d_inode, backing_path); > + inode_unlock(backing_dentry->d_inode); > + mnt_drop_write(backing_path->mnt); > + > +out_put_write: > + if (winode) > + put_write_access(winode); > + > + return err; > +} > +EXPORT_SYMBOL_GPL(backing_inode_setattr); > diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c > index 00c69707bda9..f1cd67e6e9c8 100644 > --- a/fs/overlayfs/inode.c > +++ b/fs/overlayfs/inode.c > @@ -15,16 +15,17 @@ > #include <linux/namei.h> > #include <linux/posix_acl.h> > #include <linux/posix_acl_xattr.h> > +#include <linux/backing-inode.h> > #include "overlayfs.h" > > > int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry, > struct iattr *attr) > { > + struct path backing_path; > int err; > struct ovl_fs *ofs = OVL_FS(dentry->d_sb); > bool full_copy_up = false; > - struct dentry *upperdentry; > > err = setattr_prepare(&nop_mnt_idmap, dentry, attr); > if (err) > @@ -39,57 +40,26 @@ int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry, > err = ovl_copy_up(dentry); > else > err = ovl_copy_up_with_data(dentry); > - if (!err) { > - struct inode *winode = NULL; > - > - upperdentry = ovl_dentry_upper(dentry); > - > - if (attr->ia_valid & ATTR_SIZE) { > - winode = d_inode(upperdentry); > - err = get_write_access(winode); > - if (err) > - goto out; > - } > - > - if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) > - attr->ia_valid &= ~ATTR_MODE; > > - /* > - * We might have to translate ovl file into real file object > - * once use cases emerge. For now, simply don't let underlying > - * filesystem rely on attr->ia_file > - */ > - attr->ia_valid &= ~ATTR_FILE; > - > - /* > - * If open(O_TRUNC) is done, VFS calls ->setattr with ATTR_OPEN > - * set. Overlayfs does not pass O_TRUNC flag to underlying > - * filesystem during open -> do not pass ATTR_OPEN. This > - * disables optimization in fuse which assumes open(O_TRUNC) > - * already set file size to 0. But we never passed O_TRUNC to > - * fuse. So by clearing ATTR_OPEN, fuse will be forced to send > - * setattr request to server. > - */ > - attr->ia_valid &= ~ATTR_OPEN; > + if (err) > + return err; > > - err = ovl_want_write(dentry); > - if (err) > - goto out_put_write; > + /* > + * If open(O_TRUNC) is done, VFS calls ->setattr with ATTR_OPEN > + * set. Overlayfs does not pass O_TRUNC flag to underlying > + * filesystem during open -> do not pass ATTR_OPEN. This > + * disables optimization in fuse which assumes open(O_TRUNC) > + * already set file size to 0. But we never passed O_TRUNC to > + * fuse. So by clearing ATTR_OPEN, fuse will be forced to send > + * setattr request to server. > + */ > + attr->ia_valid &= ~ATTR_OPEN; > > - inode_lock(upperdentry->d_inode); > - with_ovl_creds(dentry->d_sb) > - err = ovl_do_notify_change(ofs, upperdentry, attr); > - if (!err) > - ovl_copyattr(dentry->d_inode); > - inode_unlock(upperdentry->d_inode); > - ovl_drop_write(dentry); > + backing_path.dentry = ovl_dentry_upper(dentry); > + backing_path.mnt = ovl_upper_mnt(ofs); > > -out_put_write: > - if (winode) > - put_write_access(winode); > - } > -out: > - return err; > + return backing_inode_setattr(dentry, &backing_path, attr, > + ovl_creds(dentry->d_sb)); > } > > static void ovl_map_dev_ino(struct dentry *dentry, struct kstat *stat, int fsid) > diff --git a/include/linux/backing-inode.h b/include/linux/backing-inode.h > index 6b43cba9fabd..fd02c87e0f99 100644 > --- a/include/linux/backing-inode.h > +++ b/include/linux/backing-inode.h > @@ -11,4 +11,8 @@ > void backing_inode_copyattr(struct inode *inode, > const struct path *backing_path); > > +int backing_inode_setattr(struct dentry *dentry, > + const struct path *backing_path, > + struct iattr *attr, const struct cred *cred); > + > #endif /* _LINUX_BACKING_INODE_H */ > -- > 2.52.0 >