diff options
Diffstat (limited to 'fs/afs/dir.c')
| -rw-r--r-- | fs/afs/dir.c | 54 |
1 files changed, 26 insertions, 28 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 5889f70d4d27..7d623008157f 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
| @@ -180,6 +180,7 @@ static int afs_dir_open(struct inode *inode, struct file *file) | |||
| 180 | * get reclaimed during the iteration. | 180 | * get reclaimed during the iteration. |
| 181 | */ | 181 | */ |
| 182 | static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) | 182 | static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) |
| 183 | __acquires(&dvnode->validate_lock) | ||
| 183 | { | 184 | { |
| 184 | struct afs_read *req; | 185 | struct afs_read *req; |
| 185 | loff_t i_size; | 186 | loff_t i_size; |
| @@ -261,18 +262,21 @@ retry: | |||
| 261 | /* If we're going to reload, we need to lock all the pages to prevent | 262 | /* If we're going to reload, we need to lock all the pages to prevent |
| 262 | * races. | 263 | * races. |
| 263 | */ | 264 | */ |
| 264 | if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { | 265 | ret = -ERESTARTSYS; |
| 265 | ret = -ERESTARTSYS; | 266 | if (down_read_killable(&dvnode->validate_lock) < 0) |
| 266 | for (i = 0; i < req->nr_pages; i++) | 267 | goto error; |
| 267 | if (lock_page_killable(req->pages[i]) < 0) | ||
| 268 | goto error_unlock; | ||
| 269 | 268 | ||
| 270 | if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | 269 | if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) |
| 271 | goto success; | 270 | goto success; |
| 271 | |||
| 272 | up_read(&dvnode->validate_lock); | ||
| 273 | if (down_write_killable(&dvnode->validate_lock) < 0) | ||
| 274 | goto error; | ||
| 272 | 275 | ||
| 276 | if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { | ||
| 273 | ret = afs_fetch_data(dvnode, key, req); | 277 | ret = afs_fetch_data(dvnode, key, req); |
| 274 | if (ret < 0) | 278 | if (ret < 0) |
| 275 | goto error_unlock_all; | 279 | goto error_unlock; |
| 276 | 280 | ||
| 277 | task_io_account_read(PAGE_SIZE * req->nr_pages); | 281 | task_io_account_read(PAGE_SIZE * req->nr_pages); |
| 278 | 282 | ||
| @@ -284,33 +288,26 @@ retry: | |||
| 284 | for (i = 0; i < req->nr_pages; i++) | 288 | for (i = 0; i < req->nr_pages; i++) |
| 285 | if (!afs_dir_check_page(dvnode, req->pages[i], | 289 | if (!afs_dir_check_page(dvnode, req->pages[i], |
| 286 | req->actual_len)) | 290 | req->actual_len)) |
| 287 | goto error_unlock_all; | 291 | goto error_unlock; |
| 288 | 292 | ||
| 289 | // TODO: Trim excess pages | 293 | // TODO: Trim excess pages |
| 290 | 294 | ||
| 291 | set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); | 295 | set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); |
| 292 | } | 296 | } |
| 293 | 297 | ||
| 298 | downgrade_write(&dvnode->validate_lock); | ||
| 294 | success: | 299 | success: |
| 295 | i = req->nr_pages; | ||
| 296 | while (i > 0) | ||
| 297 | unlock_page(req->pages[--i]); | ||
| 298 | return req; | 300 | return req; |
| 299 | 301 | ||
| 300 | error_unlock_all: | ||
| 301 | i = req->nr_pages; | ||
| 302 | error_unlock: | 302 | error_unlock: |
| 303 | while (i > 0) | 303 | up_write(&dvnode->validate_lock); |
| 304 | unlock_page(req->pages[--i]); | ||
| 305 | error: | 304 | error: |
| 306 | afs_put_read(req); | 305 | afs_put_read(req); |
| 307 | _leave(" = %d", ret); | 306 | _leave(" = %d", ret); |
| 308 | return ERR_PTR(ret); | 307 | return ERR_PTR(ret); |
| 309 | 308 | ||
| 310 | content_has_grown: | 309 | content_has_grown: |
| 311 | i = req->nr_pages; | 310 | up_write(&dvnode->validate_lock); |
| 312 | while (i > 0) | ||
| 313 | unlock_page(req->pages[--i]); | ||
| 314 | afs_put_read(req); | 311 | afs_put_read(req); |
| 315 | goto retry; | 312 | goto retry; |
| 316 | } | 313 | } |
| @@ -473,6 +470,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, | |||
| 473 | } | 470 | } |
| 474 | 471 | ||
| 475 | out: | 472 | out: |
| 473 | up_read(&dvnode->validate_lock); | ||
| 476 | afs_put_read(req); | 474 | afs_put_read(req); |
| 477 | _leave(" = %d", ret); | 475 | _leave(" = %d", ret); |
| 478 | return ret; | 476 | return ret; |
| @@ -1143,7 +1141,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
| 1143 | ret = -ERESTARTSYS; | 1141 | ret = -ERESTARTSYS; |
| 1144 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1142 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
| 1145 | while (afs_select_fileserver(&fc)) { | 1143 | while (afs_select_fileserver(&fc)) { |
| 1146 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1144 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
| 1147 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, | 1145 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, |
| 1148 | &newfid, &newstatus, &newcb); | 1146 | &newfid, &newstatus, &newcb); |
| 1149 | } | 1147 | } |
| @@ -1213,7 +1211,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1213 | ret = -ERESTARTSYS; | 1211 | ret = -ERESTARTSYS; |
| 1214 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1212 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
| 1215 | while (afs_select_fileserver(&fc)) { | 1213 | while (afs_select_fileserver(&fc)) { |
| 1216 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1214 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
| 1217 | afs_fs_remove(&fc, dentry->d_name.name, true, | 1215 | afs_fs_remove(&fc, dentry->d_name.name, true, |
| 1218 | data_version); | 1216 | data_version); |
| 1219 | } | 1217 | } |
| @@ -1316,7 +1314,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 1316 | ret = -ERESTARTSYS; | 1314 | ret = -ERESTARTSYS; |
| 1317 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1315 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
| 1318 | while (afs_select_fileserver(&fc)) { | 1316 | while (afs_select_fileserver(&fc)) { |
| 1319 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1317 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
| 1320 | afs_fs_remove(&fc, dentry->d_name.name, false, | 1318 | afs_fs_remove(&fc, dentry->d_name.name, false, |
| 1321 | data_version); | 1319 | data_version); |
| 1322 | } | 1320 | } |
| @@ -1373,7 +1371,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
| 1373 | ret = -ERESTARTSYS; | 1371 | ret = -ERESTARTSYS; |
| 1374 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1372 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
| 1375 | while (afs_select_fileserver(&fc)) { | 1373 | while (afs_select_fileserver(&fc)) { |
| 1376 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1374 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
| 1377 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, | 1375 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, |
| 1378 | &newfid, &newstatus, &newcb); | 1376 | &newfid, &newstatus, &newcb); |
| 1379 | } | 1377 | } |
| @@ -1443,8 +1441,8 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
| 1443 | } | 1441 | } |
| 1444 | 1442 | ||
| 1445 | while (afs_select_fileserver(&fc)) { | 1443 | while (afs_select_fileserver(&fc)) { |
| 1446 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1444 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
| 1447 | fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break; | 1445 | fc.cb_break_2 = afs_calc_vnode_cb_break(vnode); |
| 1448 | afs_fs_link(&fc, vnode, dentry->d_name.name, data_version); | 1446 | afs_fs_link(&fc, vnode, dentry->d_name.name, data_version); |
| 1449 | } | 1447 | } |
| 1450 | 1448 | ||
| @@ -1512,7 +1510,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
| 1512 | ret = -ERESTARTSYS; | 1510 | ret = -ERESTARTSYS; |
| 1513 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1511 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
| 1514 | while (afs_select_fileserver(&fc)) { | 1512 | while (afs_select_fileserver(&fc)) { |
| 1515 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1513 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
| 1516 | afs_fs_symlink(&fc, dentry->d_name.name, | 1514 | afs_fs_symlink(&fc, dentry->d_name.name, |
| 1517 | content, data_version, | 1515 | content, data_version, |
| 1518 | &newfid, &newstatus); | 1516 | &newfid, &newstatus); |
| @@ -1588,8 +1586,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 1588 | } | 1586 | } |
| 1589 | } | 1587 | } |
| 1590 | while (afs_select_fileserver(&fc)) { | 1588 | while (afs_select_fileserver(&fc)) { |
| 1591 | fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break; | 1589 | fc.cb_break = afs_calc_vnode_cb_break(orig_dvnode); |
| 1592 | fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break; | 1590 | fc.cb_break_2 = afs_calc_vnode_cb_break(new_dvnode); |
| 1593 | afs_fs_rename(&fc, old_dentry->d_name.name, | 1591 | afs_fs_rename(&fc, old_dentry->d_name.name, |
| 1594 | new_dvnode, new_dentry->d_name.name, | 1592 | new_dvnode, new_dentry->d_name.name, |
| 1595 | orig_data_version, new_data_version); | 1593 | orig_data_version, new_data_version); |
