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

smb/server: use end_removing_noperm for for target of smb2_create_link()

Sometimes smb2_create_link() needs to remove the target before creating
the link.
It uses ksmbd_vfs_kern_locked(), and is the only user of that interface.

To match the new naming, that function is changed to
ksmbd_vfs_kern_start_removing(), and related functions or flags are also
renamed.

The lock actually happens in ksmbd_vfs_path_lookup() and that is changed
to use start_removing_noperm() - permission to perform lookup in the
parent was already checked in vfs_path_parent_lookup().

Signed-off-by: NeilBrown <neil@brown.name>
Link: https://patch.msgid.link/20251113002050.676694-8-neilb@ownmail.net
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

NeilBrown and committed by
Christian Brauner
1ead2213 c9ba789d

+19 -22
+3 -3
fs/smb/server/smb2pdu.c
··· 6084 6084 } 6085 6085 6086 6086 ksmbd_debug(SMB, "target name is %s\n", target_name); 6087 - rc = ksmbd_vfs_kern_path_locked(work, link_name, LOOKUP_NO_SYMLINKS, 6088 - &path, 0); 6087 + rc = ksmbd_vfs_kern_path_start_removing(work, link_name, LOOKUP_NO_SYMLINKS, 6088 + &path, 0); 6089 6089 if (rc) { 6090 6090 if (rc != -ENOENT) 6091 6091 goto out; ··· 6103 6103 ksmbd_debug(SMB, "link already exists\n"); 6104 6104 goto out; 6105 6105 } 6106 - ksmbd_vfs_kern_path_unlock(&path); 6106 + ksmbd_vfs_kern_path_end_removing(&path); 6107 6107 } 6108 6108 rc = ksmbd_vfs_link(work, target_name, link_name); 6109 6109 if (rc)
+12 -15
fs/smb/server/vfs.c
··· 69 69 70 70 static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf, 71 71 char *pathname, unsigned int flags, 72 - struct path *path, bool do_lock) 72 + struct path *path, bool for_remove) 73 73 { 74 74 struct qstr last; 75 75 struct filename *filename __free(putname) = NULL; ··· 99 99 return -ENOENT; 100 100 } 101 101 102 - if (do_lock) { 102 + if (for_remove) { 103 103 err = mnt_want_write(path->mnt); 104 104 if (err) { 105 105 path_put(path); 106 106 return -ENOENT; 107 107 } 108 108 109 - inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); 110 - d = lookup_one_qstr_excl(&last, path->dentry, 0); 109 + d = start_removing_noperm(path->dentry, &last); 111 110 112 111 if (!IS_ERR(d)) { 113 112 dput(path->dentry); 114 113 path->dentry = d; 115 114 return 0; 116 115 } 117 - inode_unlock(path->dentry->d_inode); 118 116 mnt_drop_write(path->mnt); 119 117 path_put(path); 120 118 return -ENOENT; ··· 1205 1207 static 1206 1208 int __ksmbd_vfs_kern_path(struct ksmbd_work *work, char *filepath, 1207 1209 unsigned int flags, 1208 - struct path *path, bool caseless, bool do_lock) 1210 + struct path *path, bool caseless, bool for_remove) 1209 1211 { 1210 1212 struct ksmbd_share_config *share_conf = work->tcon->share_conf; 1211 1213 struct path parent_path; ··· 1213 1215 int err; 1214 1216 1215 1217 retry: 1216 - err = ksmbd_vfs_path_lookup(share_conf, filepath, flags, path, do_lock); 1218 + err = ksmbd_vfs_path_lookup(share_conf, filepath, flags, path, for_remove); 1217 1219 if (!err || !caseless) 1218 1220 return err; 1219 1221 ··· 1284 1286 } 1285 1287 1286 1288 /** 1287 - * ksmbd_vfs_kern_path_locked() - lookup a file and get path info 1289 + * ksmbd_vfs_kern_path_start_remove() - lookup a file and get path info prior to removal 1288 1290 * @work: work 1289 1291 * @filepath: file path that is relative to share 1290 1292 * @flags: lookup flags ··· 1296 1298 * filesystem will have been gained. 1297 1299 * Return: 0 on if file was found, otherwise error 1298 1300 */ 1299 - int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *filepath, 1300 - unsigned int flags, 1301 - struct path *path, bool caseless) 1301 + int ksmbd_vfs_kern_path_start_removing(struct ksmbd_work *work, char *filepath, 1302 + unsigned int flags, 1303 + struct path *path, bool caseless) 1302 1304 { 1303 1305 return __ksmbd_vfs_kern_path(work, filepath, flags, path, 1304 1306 caseless, true); 1305 1307 } 1306 1308 1307 - void ksmbd_vfs_kern_path_unlock(const struct path *path) 1309 + void ksmbd_vfs_kern_path_end_removing(const struct path *path) 1308 1310 { 1309 - /* While lock is still held, ->d_parent is safe */ 1310 - inode_unlock(d_inode(path->dentry->d_parent)); 1311 + end_removing(path->dentry); 1311 1312 mnt_drop_write(path->mnt); 1312 - path_put(path); 1313 + mntput(path->mnt); 1313 1314 } 1314 1315 1315 1316 struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
+4 -4
fs/smb/server/vfs.h
··· 120 120 int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name, 121 121 unsigned int flags, 122 122 struct path *path, bool caseless); 123 - int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, 124 - unsigned int flags, 125 - struct path *path, bool caseless); 126 - void ksmbd_vfs_kern_path_unlock(const struct path *path); 123 + int ksmbd_vfs_kern_path_start_removing(struct ksmbd_work *work, char *name, 124 + unsigned int flags, 125 + struct path *path, bool caseless); 126 + void ksmbd_vfs_kern_path_end_removing(const struct path *path); 127 127 struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, 128 128 const char *name, 129 129 unsigned int flags,