|
@@ -180,6 +180,7 @@ static int afs_dir_open(struct inode *inode, struct file *file)
|
|
|
* get reclaimed during the iteration.
|
|
|
*/
|
|
|
static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
|
|
|
+ __acquires(&dvnode->validate_lock)
|
|
|
{
|
|
|
struct afs_read *req;
|
|
|
loff_t i_size;
|
|
@@ -261,18 +262,21 @@ retry:
|
|
|
/* If we're going to reload, we need to lock all the pages to prevent
|
|
|
* races.
|
|
|
*/
|
|
|
- if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
|
|
|
- ret = -ERESTARTSYS;
|
|
|
- for (i = 0; i < req->nr_pages; i++)
|
|
|
- if (lock_page_killable(req->pages[i]) < 0)
|
|
|
- goto error_unlock;
|
|
|
+ ret = -ERESTARTSYS;
|
|
|
+ if (down_read_killable(&dvnode->validate_lock) < 0)
|
|
|
+ goto error;
|
|
|
|
|
|
- if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
|
|
|
- goto success;
|
|
|
+ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
|
|
|
+ goto success;
|
|
|
+
|
|
|
+ up_read(&dvnode->validate_lock);
|
|
|
+ if (down_write_killable(&dvnode->validate_lock) < 0)
|
|
|
+ goto error;
|
|
|
|
|
|
+ if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
|
|
|
ret = afs_fetch_data(dvnode, key, req);
|
|
|
if (ret < 0)
|
|
|
- goto error_unlock_all;
|
|
|
+ goto error_unlock;
|
|
|
|
|
|
task_io_account_read(PAGE_SIZE * req->nr_pages);
|
|
|
|
|
@@ -284,33 +288,26 @@ retry:
|
|
|
for (i = 0; i < req->nr_pages; i++)
|
|
|
if (!afs_dir_check_page(dvnode, req->pages[i],
|
|
|
req->actual_len))
|
|
|
- goto error_unlock_all;
|
|
|
+ goto error_unlock;
|
|
|
|
|
|
// TODO: Trim excess pages
|
|
|
|
|
|
set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags);
|
|
|
}
|
|
|
|
|
|
+ downgrade_write(&dvnode->validate_lock);
|
|
|
success:
|
|
|
- i = req->nr_pages;
|
|
|
- while (i > 0)
|
|
|
- unlock_page(req->pages[--i]);
|
|
|
return req;
|
|
|
|
|
|
-error_unlock_all:
|
|
|
- i = req->nr_pages;
|
|
|
error_unlock:
|
|
|
- while (i > 0)
|
|
|
- unlock_page(req->pages[--i]);
|
|
|
+ up_write(&dvnode->validate_lock);
|
|
|
error:
|
|
|
afs_put_read(req);
|
|
|
_leave(" = %d", ret);
|
|
|
return ERR_PTR(ret);
|
|
|
|
|
|
content_has_grown:
|
|
|
- i = req->nr_pages;
|
|
|
- while (i > 0)
|
|
|
- unlock_page(req->pages[--i]);
|
|
|
+ up_write(&dvnode->validate_lock);
|
|
|
afs_put_read(req);
|
|
|
goto retry;
|
|
|
}
|
|
@@ -473,6 +470,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
+ up_read(&dvnode->validate_lock);
|
|
|
afs_put_read(req);
|
|
|
_leave(" = %d", ret);
|
|
|
return ret;
|