@@ -63,13 +63,13 @@ int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child)
6363
6464static int ksmbd_vfs_path_lookup_locked (struct ksmbd_share_config * share_conf ,
6565 char * pathname , unsigned int flags ,
66+ struct path * parent_path ,
6667 struct path * path )
6768{
6869 struct qstr last ;
6970 struct filename * filename ;
7071 struct path * root_share_path = & share_conf -> vfs_path ;
7172 int err , type ;
72- struct path parent_path ;
7373 struct dentry * d ;
7474
7575 if (pathname [0 ] == '\0' ) {
@@ -84,21 +84,21 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf,
8484 return PTR_ERR (filename );
8585
8686 err = vfs_path_parent_lookup (filename , flags ,
87- & parent_path , & last , & type ,
87+ parent_path , & last , & type ,
8888 root_share_path );
8989 if (err ) {
9090 putname (filename );
9191 return err ;
9292 }
9393
9494 if (unlikely (type != LAST_NORM )) {
95- path_put (& parent_path );
95+ path_put (parent_path );
9696 putname (filename );
9797 return - ENOENT ;
9898 }
9999
100- inode_lock_nested (parent_path . dentry -> d_inode , I_MUTEX_PARENT );
101- d = lookup_one_qstr_excl (& last , parent_path . dentry , 0 );
100+ inode_lock_nested (parent_path -> dentry -> d_inode , I_MUTEX_PARENT );
101+ d = lookup_one_qstr_excl (& last , parent_path -> dentry , 0 );
102102 if (IS_ERR (d ))
103103 goto err_out ;
104104
@@ -108,15 +108,22 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf,
108108 }
109109
110110 path -> dentry = d ;
111- path -> mnt = share_conf -> vfs_path .mnt ;
112- path_put (& parent_path );
113- putname (filename );
111+ path -> mnt = mntget (parent_path -> mnt );
112+
113+ if (test_share_config_flag (share_conf , KSMBD_SHARE_FLAG_CROSSMNT )) {
114+ err = follow_down (path , 0 );
115+ if (err < 0 ) {
116+ path_put (path );
117+ goto err_out ;
118+ }
119+ }
114120
121+ putname (filename );
115122 return 0 ;
116123
117124err_out :
118- inode_unlock (parent_path . dentry -> d_inode );
119- path_put (& parent_path );
125+ inode_unlock (d_inode ( parent_path -> dentry ) );
126+ path_put (parent_path );
120127 putname (filename );
121128 return - ENOENT ;
122129}
@@ -1195,14 +1202,14 @@ static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name,
11951202 * Return: 0 on success, otherwise error
11961203 */
11971204int ksmbd_vfs_kern_path_locked (struct ksmbd_work * work , char * name ,
1198- unsigned int flags , struct path * path ,
1199- bool caseless )
1205+ unsigned int flags , struct path * parent_path ,
1206+ struct path * path , bool caseless )
12001207{
12011208 struct ksmbd_share_config * share_conf = work -> tcon -> share_conf ;
12021209 int err ;
1203- struct path parent_path ;
12041210
1205- err = ksmbd_vfs_path_lookup_locked (share_conf , name , flags , path );
1211+ err = ksmbd_vfs_path_lookup_locked (share_conf , name , flags , parent_path ,
1212+ path );
12061213 if (!err )
12071214 return 0 ;
12081215
@@ -1217,10 +1224,10 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
12171224 path_len = strlen (filepath );
12181225 remain_len = path_len ;
12191226
1220- parent_path = share_conf -> vfs_path ;
1221- path_get (& parent_path );
1227+ * parent_path = share_conf -> vfs_path ;
1228+ path_get (parent_path );
12221229
1223- while (d_can_lookup (parent_path . dentry )) {
1230+ while (d_can_lookup (parent_path -> dentry )) {
12241231 char * filename = filepath + path_len - remain_len ;
12251232 char * next = strchrnul (filename , '/' );
12261233 size_t filename_len = next - filename ;
@@ -1229,7 +1236,7 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
12291236 if (filename_len == 0 )
12301237 break ;
12311238
1232- err = ksmbd_vfs_lookup_in_dir (& parent_path , filename ,
1239+ err = ksmbd_vfs_lookup_in_dir (parent_path , filename ,
12331240 filename_len ,
12341241 work -> conn -> um );
12351242 if (err )
@@ -1246,25 +1253,26 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
12461253 goto out2 ;
12471254 else if (is_last )
12481255 goto out1 ;
1249- path_put (& parent_path );
1250- parent_path = * path ;
1256+ path_put (parent_path );
1257+ * parent_path = * path ;
12511258
12521259 next [0 ] = '/' ;
12531260 remain_len -= filename_len + 1 ;
12541261 }
12551262
12561263 err = - EINVAL ;
12571264out2 :
1258- path_put (& parent_path );
1265+ path_put (parent_path );
12591266out1 :
12601267 kfree (filepath );
12611268 }
12621269
12631270 if (!err ) {
1264- err = ksmbd_vfs_lock_parent (parent_path .dentry , path -> dentry );
1265- if (err )
1266- dput (path -> dentry );
1267- path_put (& parent_path );
1271+ err = ksmbd_vfs_lock_parent (parent_path -> dentry , path -> dentry );
1272+ if (err ) {
1273+ path_put (path );
1274+ path_put (parent_path );
1275+ }
12681276 }
12691277 return err ;
12701278}
0 commit comments