Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

vfs: break parent dir delegations in open(..., O_CREAT) codepath

In order to add directory delegation support, we need to break
delegations on the parent whenever there is going to be a change in the
directory.

Add a delegated_inode parameter to lookup_open and have it break the
delegation. Then, open_last_lookups can wait for the delegation break
and retry the call to lookup_open once it's done.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: NeilBrown <neil@brown.name>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20251111-dir-deleg-ro-v6-8-52f3feebb2f2@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Jeff Layton and committed by
Christian Brauner
134796f4 4fa76319

+18 -4
+18 -4
fs/namei.c
··· 3697 3697 */ 3698 3698 static struct dentry *lookup_open(struct nameidata *nd, struct file *file, 3699 3699 const struct open_flags *op, 3700 - bool got_write) 3700 + bool got_write, struct delegated_inode *delegated_inode) 3701 3701 { 3702 3702 struct mnt_idmap *idmap; 3703 3703 struct dentry *dir = nd->path.dentry; ··· 3786 3786 3787 3787 /* Negative dentry, just create the file */ 3788 3788 if (!dentry->d_inode && (open_flag & O_CREAT)) { 3789 + /* but break the directory lease first! */ 3790 + error = try_break_deleg(dir_inode, delegated_inode); 3791 + if (error) 3792 + goto out_dput; 3793 + 3789 3794 file->f_mode |= FMODE_CREATED; 3790 3795 audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE); 3791 3796 if (!dir_inode->i_op->create) { ··· 3853 3848 static const char *open_last_lookups(struct nameidata *nd, 3854 3849 struct file *file, const struct open_flags *op) 3855 3850 { 3851 + struct delegated_inode delegated_inode = { }; 3856 3852 struct dentry *dir = nd->path.dentry; 3857 3853 int open_flag = op->open_flag; 3858 3854 bool got_write = false; ··· 3885 3879 return ERR_PTR(-ECHILD); 3886 3880 } 3887 3881 } 3888 - 3882 + retry: 3889 3883 if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) { 3890 3884 got_write = !mnt_want_write(nd->path.mnt); 3891 3885 /* ··· 3898 3892 inode_lock(dir->d_inode); 3899 3893 else 3900 3894 inode_lock_shared(dir->d_inode); 3901 - dentry = lookup_open(nd, file, op, got_write); 3895 + dentry = lookup_open(nd, file, op, got_write, &delegated_inode); 3902 3896 if (!IS_ERR(dentry)) { 3903 3897 if (file->f_mode & FMODE_CREATED) 3904 3898 fsnotify_create(dir->d_inode, dentry); ··· 3913 3907 if (got_write) 3914 3908 mnt_drop_write(nd->path.mnt); 3915 3909 3916 - if (IS_ERR(dentry)) 3910 + if (IS_ERR(dentry)) { 3911 + if (is_delegated(&delegated_inode)) { 3912 + int error = break_deleg_wait(&delegated_inode); 3913 + 3914 + if (!error) 3915 + goto retry; 3916 + return ERR_PTR(error); 3917 + } 3917 3918 return ERR_CAST(dentry); 3919 + } 3918 3920 3919 3921 if (file->f_mode & (FMODE_OPENED | FMODE_CREATED)) { 3920 3922 dput(nd->path.dentry);