@@ -1162,7 +1162,6 @@ static int fuse_direntplus_link(struct file *file,
1162
1162
struct fuse_direntplus * direntplus ,
1163
1163
u64 attr_version )
1164
1164
{
1165
- int err ;
1166
1165
struct fuse_entry_out * o = & direntplus -> entry_out ;
1167
1166
struct fuse_dirent * dirent = & direntplus -> dirent ;
1168
1167
struct dentry * parent = file -> f_path .dentry ;
@@ -1172,6 +1171,7 @@ static int fuse_direntplus_link(struct file *file,
1172
1171
struct inode * dir = d_inode (parent );
1173
1172
struct fuse_conn * fc ;
1174
1173
struct inode * inode ;
1174
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK (wq );
1175
1175
1176
1176
if (!o -> nodeid ) {
1177
1177
/*
@@ -1204,65 +1204,61 @@ static int fuse_direntplus_link(struct file *file,
1204
1204
1205
1205
name .hash = full_name_hash (name .name , name .len );
1206
1206
dentry = d_lookup (parent , & name );
1207
- if (dentry ) {
1207
+ if (!dentry ) {
1208
+ retry :
1209
+ dentry = d_alloc_parallel (parent , & name , & wq );
1210
+ if (IS_ERR (dentry ))
1211
+ return PTR_ERR (dentry );
1212
+ }
1213
+ if (!d_in_lookup (dentry )) {
1214
+ struct fuse_inode * fi ;
1208
1215
inode = d_inode (dentry );
1209
- if (!inode ) {
1210
- d_drop (dentry );
1211
- } else if (get_node_id (inode ) != o -> nodeid ||
1212
- ((o -> attr .mode ^ inode -> i_mode ) & S_IFMT )) {
1216
+ if (!inode ||
1217
+ get_node_id (inode ) != o -> nodeid ||
1218
+ ((o -> attr .mode ^ inode -> i_mode ) & S_IFMT )) {
1213
1219
d_invalidate (dentry );
1214
- } else if (is_bad_inode (inode )) {
1215
- err = - EIO ;
1216
- goto out ;
1217
- } else {
1218
- struct fuse_inode * fi ;
1219
- fi = get_fuse_inode (inode );
1220
- spin_lock (& fc -> lock );
1221
- fi -> nlookup ++ ;
1222
- spin_unlock (& fc -> lock );
1223
-
1224
- fuse_change_attributes (inode , & o -> attr ,
1225
- entry_attr_timeout (o ),
1226
- attr_version );
1227
-
1228
- /*
1229
- * The other branch to 'found' comes via fuse_iget()
1230
- * which bumps nlookup inside
1231
- */
1232
- goto found ;
1220
+ dput (dentry );
1221
+ goto retry ;
1222
+ }
1223
+ if (is_bad_inode (inode )) {
1224
+ dput (dentry );
1225
+ return - EIO ;
1233
1226
}
1234
- dput (dentry );
1235
- }
1236
-
1237
- dentry = d_alloc (parent , & name );
1238
- err = - ENOMEM ;
1239
- if (!dentry )
1240
- goto out ;
1241
1227
1242
- inode = fuse_iget ( dir -> i_sb , o -> nodeid , o -> generation ,
1243
- & o -> attr , entry_attr_timeout ( o ), attr_version );
1244
- if (! inode )
1245
- goto out ;
1228
+ fi = get_fuse_inode ( inode );
1229
+ spin_lock ( & fc -> lock );
1230
+ fi -> nlookup ++ ;
1231
+ spin_unlock ( & fc -> lock ) ;
1246
1232
1247
- alias = d_splice_alias (inode , dentry );
1248
- err = PTR_ERR (alias );
1249
- if (IS_ERR (alias ))
1250
- goto out ;
1233
+ fuse_change_attributes (inode , & o -> attr ,
1234
+ entry_attr_timeout (o ),
1235
+ attr_version );
1236
+ /*
1237
+ * The other branch comes via fuse_iget()
1238
+ * which bumps nlookup inside
1239
+ */
1240
+ } else {
1241
+ inode = fuse_iget (dir -> i_sb , o -> nodeid , o -> generation ,
1242
+ & o -> attr , entry_attr_timeout (o ),
1243
+ attr_version );
1244
+ if (!inode )
1245
+ inode = ERR_PTR (- ENOMEM );
1251
1246
1252
- if (alias ) {
1253
- dput (dentry );
1254
- dentry = alias ;
1247
+ alias = d_splice_alias (inode , dentry );
1248
+ d_lookup_done (dentry );
1249
+ if (alias ) {
1250
+ dput (dentry );
1251
+ dentry = alias ;
1252
+ }
1253
+ if (IS_ERR (dentry ))
1254
+ return PTR_ERR (dentry );
1255
1255
}
1256
-
1257
- found :
1258
1256
if (fc -> readdirplus_auto )
1259
1257
set_bit (FUSE_I_INIT_RDPLUS , & get_fuse_inode (inode )-> state );
1260
1258
fuse_change_entry_timeout (dentry , o );
1261
1259
1262
- err = 0 ;
1263
- out :
1264
1260
dput (dentry );
1265
- return err ;
1261
+ return 0 ;
1266
1262
}
1267
1263
1268
1264
static int parse_dirplusfile (char * buf , size_t nbytes , struct file * file ,
@@ -1892,7 +1888,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
1892
1888
static const struct file_operations fuse_dir_operations = {
1893
1889
.llseek = generic_file_llseek ,
1894
1890
.read = generic_read_dir ,
1895
- .iterate = fuse_readdir ,
1891
+ .iterate_shared = fuse_readdir ,
1896
1892
.open = fuse_dir_open ,
1897
1893
.release = fuse_dir_release ,
1898
1894
.fsync = fuse_dir_fsync ,
0 commit comments