|
@@ -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;
|
|
@@ -1143,7 +1141,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
|
ret = -ERESTARTSYS;
|
|
|
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
|
|
|
while (afs_select_fileserver(&fc)) {
|
|
|
- fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
|
|
|
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
|
|
|
afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
|
|
|
&newfid, &newstatus, &newcb);
|
|
|
}
|
|
@@ -1213,7 +1211,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
|
ret = -ERESTARTSYS;
|
|
|
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
|
|
|
while (afs_select_fileserver(&fc)) {
|
|
|
- fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
|
|
|
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
|
|
|
afs_fs_remove(&fc, dentry->d_name.name, true,
|
|
|
data_version);
|
|
|
}
|
|
@@ -1316,7 +1314,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
|
|
|
ret = -ERESTARTSYS;
|
|
|
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
|
|
|
while (afs_select_fileserver(&fc)) {
|
|
|
- fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
|
|
|
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
|
|
|
afs_fs_remove(&fc, dentry->d_name.name, false,
|
|
|
data_version);
|
|
|
}
|
|
@@ -1373,7 +1371,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|
|
ret = -ERESTARTSYS;
|
|
|
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
|
|
|
while (afs_select_fileserver(&fc)) {
|
|
|
- fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
|
|
|
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
|
|
|
afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
|
|
|
&newfid, &newstatus, &newcb);
|
|
|
}
|
|
@@ -1443,8 +1441,8 @@ static int afs_link(struct dentry *from, struct inode *dir,
|
|
|
}
|
|
|
|
|
|
while (afs_select_fileserver(&fc)) {
|
|
|
- fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
|
|
|
- fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break;
|
|
|
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
|
|
|
+ fc.cb_break_2 = afs_calc_vnode_cb_break(vnode);
|
|
|
afs_fs_link(&fc, vnode, dentry->d_name.name, data_version);
|
|
|
}
|
|
|
|
|
@@ -1512,7 +1510,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
|
|
|
ret = -ERESTARTSYS;
|
|
|
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
|
|
|
while (afs_select_fileserver(&fc)) {
|
|
|
- fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
|
|
|
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
|
|
|
afs_fs_symlink(&fc, dentry->d_name.name,
|
|
|
content, data_version,
|
|
|
&newfid, &newstatus);
|
|
@@ -1588,8 +1586,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
}
|
|
|
}
|
|
|
while (afs_select_fileserver(&fc)) {
|
|
|
- fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break;
|
|
|
- fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break;
|
|
|
+ fc.cb_break = afs_calc_vnode_cb_break(orig_dvnode);
|
|
|
+ fc.cb_break_2 = afs_calc_vnode_cb_break(new_dvnode);
|
|
|
afs_fs_rename(&fc, old_dentry->d_name.name,
|
|
|
new_dvnode, new_dentry->d_name.name,
|
|
|
orig_data_version, new_data_version);
|