Skip to content

Commit deed1bf

Browse files
Russell KingAl Viro
authored andcommitted
fs/adfs: dir: update directory locking
Update directory locking such that it covers the validation of the directory, which could fail if another thread is concurrently writing to the same directory. Since we may sleep, we need to use a rwsem rather than a rw spinlock. Signed-off-by: Russell King <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent c3c8149 commit deed1bf

File tree

1 file changed

+29
-26
lines changed

1 file changed

+29
-26
lines changed

fs/adfs/dir.c

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
/*
1313
* For future. This should probably be per-directory.
1414
*/
15-
static DEFINE_RWLOCK(adfs_dir_lock);
15+
static DECLARE_RWSEM(adfs_dir_rwsem);
1616

1717
int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset,
1818
size_t len)
@@ -232,39 +232,40 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
232232
if (ctx->pos >> 32)
233233
return 0;
234234

235+
down_read(&adfs_dir_rwsem);
235236
ret = adfs_dir_read_inode(sb, inode, &dir);
236237
if (ret)
237-
return ret;
238+
goto unlock;
238239

239240
if (ctx->pos == 0) {
240241
if (!dir_emit_dot(file, ctx))
241-
goto free_out;
242+
goto unlock_relse;
242243
ctx->pos = 1;
243244
}
244245
if (ctx->pos == 1) {
245246
if (!dir_emit(ctx, "..", 2, dir.parent_id, DT_DIR))
246-
goto free_out;
247+
goto unlock_relse;
247248
ctx->pos = 2;
248249
}
249250

250-
read_lock(&adfs_dir_lock);
251-
252251
ret = ops->setpos(&dir, ctx->pos - 2);
253252
if (ret)
254-
goto unlock_out;
253+
goto unlock_relse;
255254
while (ops->getnext(&dir, &obj) == 0) {
256255
if (!dir_emit(ctx, obj.name, obj.name_len,
257256
obj.indaddr, DT_UNKNOWN))
258257
break;
259258
ctx->pos++;
260259
}
261260

262-
unlock_out:
263-
read_unlock(&adfs_dir_lock);
264-
265-
free_out:
261+
unlock_relse:
262+
up_read(&adfs_dir_rwsem);
266263
adfs_dir_relse(&dir);
267264
return ret;
265+
266+
unlock:
267+
up_read(&adfs_dir_rwsem);
268+
return ret;
268269
}
269270

270271
int
@@ -281,13 +282,13 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
281282
if (!ops->update)
282283
return -EINVAL;
283284

285+
down_write(&adfs_dir_rwsem);
284286
ret = adfs_dir_read(sb, obj->parent_id, 0, &dir);
285287
if (ret)
286-
goto out;
288+
goto unlock;
287289

288-
write_lock(&adfs_dir_lock);
289290
ret = ops->update(&dir, obj);
290-
write_unlock(&adfs_dir_lock);
291+
up_write(&adfs_dir_rwsem);
291292

292293
if (ret == 0)
293294
adfs_dir_mark_dirty(&dir);
@@ -299,7 +300,10 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
299300
}
300301

301302
adfs_dir_relse(&dir);
302-
out:
303+
return ret;
304+
305+
unlock:
306+
up_write(&adfs_dir_rwsem);
303307
#endif
304308
return ret;
305309
}
@@ -336,17 +340,14 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
336340
u32 name_len;
337341
int ret;
338342

343+
down_read(&adfs_dir_rwsem);
339344
ret = adfs_dir_read_inode(sb, inode, &dir);
340345
if (ret)
341-
goto out;
342-
343-
obj->parent_id = inode->i_ino;
344-
345-
read_lock(&adfs_dir_lock);
346+
goto unlock;
346347

347348
ret = ops->setpos(&dir, 0);
348349
if (ret)
349-
goto unlock_out;
350+
goto unlock_relse;
350351

351352
ret = -ENOENT;
352353
name = qstr->name;
@@ -357,13 +358,15 @@ static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
357358
break;
358359
}
359360
}
361+
obj->parent_id = inode->i_ino;
360362

361-
unlock_out:
362-
read_unlock(&adfs_dir_lock);
363-
364-
free_out:
363+
unlock_relse:
364+
up_read(&adfs_dir_rwsem);
365365
adfs_dir_relse(&dir);
366-
out:
366+
return ret;
367+
368+
unlock:
369+
up_read(&adfs_dir_rwsem);
367370
return ret;
368371
}
369372

0 commit comments

Comments
 (0)