diff options
-rw-r--r-- | fs/afs/dir.c | 84 |
1 files changed, 70 insertions, 14 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 618e26cea887..81207dc3c997 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -440,7 +440,7 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode, | |||
440 | * iterate through the data blob that lists the contents of an AFS directory | 440 | * iterate through the data blob that lists the contents of an AFS directory |
441 | */ | 441 | */ |
442 | static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, | 442 | static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, |
443 | struct key *key) | 443 | struct key *key, afs_dataversion_t *_dir_version) |
444 | { | 444 | { |
445 | struct afs_vnode *dvnode = AFS_FS_I(dir); | 445 | struct afs_vnode *dvnode = AFS_FS_I(dir); |
446 | struct afs_xdr_dir_page *dbuf; | 446 | struct afs_xdr_dir_page *dbuf; |
@@ -460,6 +460,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, | |||
460 | req = afs_read_dir(dvnode, key); | 460 | req = afs_read_dir(dvnode, key); |
461 | if (IS_ERR(req)) | 461 | if (IS_ERR(req)) |
462 | return PTR_ERR(req); | 462 | return PTR_ERR(req); |
463 | *_dir_version = req->data_version; | ||
463 | 464 | ||
464 | /* round the file position up to the next entry boundary */ | 465 | /* round the file position up to the next entry boundary */ |
465 | ctx->pos += sizeof(union afs_xdr_dirent) - 1; | 466 | ctx->pos += sizeof(union afs_xdr_dirent) - 1; |
@@ -514,7 +515,10 @@ out: | |||
514 | */ | 515 | */ |
515 | static int afs_readdir(struct file *file, struct dir_context *ctx) | 516 | static int afs_readdir(struct file *file, struct dir_context *ctx) |
516 | { | 517 | { |
517 | return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file)); | 518 | afs_dataversion_t dir_version; |
519 | |||
520 | return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file), | ||
521 | &dir_version); | ||
518 | } | 522 | } |
519 | 523 | ||
520 | /* | 524 | /* |
@@ -555,7 +559,8 @@ static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, | |||
555 | * - just returns the FID the dentry name maps to if found | 559 | * - just returns the FID the dentry name maps to if found |
556 | */ | 560 | */ |
557 | static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry, | 561 | static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry, |
558 | struct afs_fid *fid, struct key *key) | 562 | struct afs_fid *fid, struct key *key, |
563 | afs_dataversion_t *_dir_version) | ||
559 | { | 564 | { |
560 | struct afs_super_info *as = dir->i_sb->s_fs_info; | 565 | struct afs_super_info *as = dir->i_sb->s_fs_info; |
561 | struct afs_lookup_one_cookie cookie = { | 566 | struct afs_lookup_one_cookie cookie = { |
@@ -568,7 +573,7 @@ static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry, | |||
568 | _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); | 573 | _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); |
569 | 574 | ||
570 | /* search the directory */ | 575 | /* search the directory */ |
571 | ret = afs_dir_iterate(dir, &cookie.ctx, key); | 576 | ret = afs_dir_iterate(dir, &cookie.ctx, key, _dir_version); |
572 | if (ret < 0) { | 577 | if (ret < 0) { |
573 | _leave(" = %d [iter]", ret); | 578 | _leave(" = %d [iter]", ret); |
574 | return ret; | 579 | return ret; |
@@ -642,6 +647,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
642 | struct afs_server *server; | 647 | struct afs_server *server; |
643 | struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; | 648 | struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; |
644 | struct inode *inode = NULL, *ti; | 649 | struct inode *inode = NULL, *ti; |
650 | afs_dataversion_t data_version = READ_ONCE(dvnode->status.data_version); | ||
645 | int ret, i; | 651 | int ret, i; |
646 | 652 | ||
647 | _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); | 653 | _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); |
@@ -669,12 +675,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
669 | cookie->fids[i].vid = as->volume->vid; | 675 | cookie->fids[i].vid = as->volume->vid; |
670 | 676 | ||
671 | /* search the directory */ | 677 | /* search the directory */ |
672 | ret = afs_dir_iterate(dir, &cookie->ctx, key); | 678 | ret = afs_dir_iterate(dir, &cookie->ctx, key, &data_version); |
673 | if (ret < 0) { | 679 | if (ret < 0) { |
674 | inode = ERR_PTR(ret); | 680 | inode = ERR_PTR(ret); |
675 | goto out; | 681 | goto out; |
676 | } | 682 | } |
677 | 683 | ||
684 | dentry->d_fsdata = (void *)(unsigned long)data_version; | ||
685 | |||
678 | inode = ERR_PTR(-ENOENT); | 686 | inode = ERR_PTR(-ENOENT); |
679 | if (!cookie->found) | 687 | if (!cookie->found) |
680 | goto out; | 688 | goto out; |
@@ -968,7 +976,8 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) | |||
968 | struct dentry *parent; | 976 | struct dentry *parent; |
969 | struct inode *inode; | 977 | struct inode *inode; |
970 | struct key *key; | 978 | struct key *key; |
971 | long dir_version, de_version; | 979 | afs_dataversion_t dir_version; |
980 | long de_version; | ||
972 | int ret; | 981 | int ret; |
973 | 982 | ||
974 | if (flags & LOOKUP_RCU) | 983 | if (flags & LOOKUP_RCU) |
@@ -1014,20 +1023,20 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) | |||
1014 | * on a 32-bit system, we only have 32 bits in the dentry to store the | 1023 | * on a 32-bit system, we only have 32 bits in the dentry to store the |
1015 | * version. | 1024 | * version. |
1016 | */ | 1025 | */ |
1017 | dir_version = (long)dir->status.data_version; | 1026 | dir_version = dir->status.data_version; |
1018 | de_version = (long)dentry->d_fsdata; | 1027 | de_version = (long)dentry->d_fsdata; |
1019 | if (de_version == dir_version) | 1028 | if (de_version == (long)dir_version) |
1020 | goto out_valid_noupdate; | 1029 | goto out_valid_noupdate; |
1021 | 1030 | ||
1022 | dir_version = (long)dir->invalid_before; | 1031 | dir_version = dir->invalid_before; |
1023 | if (de_version - dir_version >= 0) | 1032 | if (de_version - (long)dir_version >= 0) |
1024 | goto out_valid; | 1033 | goto out_valid; |
1025 | 1034 | ||
1026 | _debug("dir modified"); | 1035 | _debug("dir modified"); |
1027 | afs_stat_v(dir, n_reval); | 1036 | afs_stat_v(dir, n_reval); |
1028 | 1037 | ||
1029 | /* search the directory for this vnode */ | 1038 | /* search the directory for this vnode */ |
1030 | ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key); | 1039 | ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key, &dir_version); |
1031 | switch (ret) { | 1040 | switch (ret) { |
1032 | case 0: | 1041 | case 0: |
1033 | /* the filename maps to something */ | 1042 | /* the filename maps to something */ |
@@ -1080,7 +1089,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) | |||
1080 | } | 1089 | } |
1081 | 1090 | ||
1082 | out_valid: | 1091 | out_valid: |
1083 | dentry->d_fsdata = (void *)dir_version; | 1092 | dentry->d_fsdata = (void *)(unsigned long)dir_version; |
1084 | out_valid_noupdate: | 1093 | out_valid_noupdate: |
1085 | dput(parent); | 1094 | dput(parent); |
1086 | key_put(key); | 1095 | key_put(key); |
@@ -1187,6 +1196,20 @@ static void afs_prep_for_new_inode(struct afs_fs_cursor *fc, | |||
1187 | } | 1196 | } |
1188 | 1197 | ||
1189 | /* | 1198 | /* |
1199 | * Note that a dentry got changed. We need to set d_fsdata to the data version | ||
1200 | * number derived from the result of the operation. It doesn't matter if | ||
1201 | * d_fsdata goes backwards as we'll just revalidate. | ||
1202 | */ | ||
1203 | static void afs_update_dentry_version(struct afs_fs_cursor *fc, | ||
1204 | struct dentry *dentry, | ||
1205 | struct afs_status_cb *scb) | ||
1206 | { | ||
1207 | if (fc->ac.error == 0) | ||
1208 | dentry->d_fsdata = | ||
1209 | (void *)(unsigned long)scb->status.data_version; | ||
1210 | } | ||
1211 | |||
1212 | /* | ||
1190 | * create a directory on an AFS filesystem | 1213 | * create a directory on an AFS filesystem |
1191 | */ | 1214 | */ |
1192 | static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | 1215 | static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) |
@@ -1228,6 +1251,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
1228 | afs_check_for_remote_deletion(&fc, dvnode); | 1251 | afs_check_for_remote_deletion(&fc, dvnode); |
1229 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break, | 1252 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break, |
1230 | &data_version, &scb[0]); | 1253 | &data_version, &scb[0]); |
1254 | afs_update_dentry_version(&fc, dentry, &scb[0]); | ||
1231 | afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); | 1255 | afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); |
1232 | ret = afs_end_vnode_operation(&fc); | 1256 | ret = afs_end_vnode_operation(&fc); |
1233 | if (ret < 0) | 1257 | if (ret < 0) |
@@ -1320,6 +1344,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1320 | 1344 | ||
1321 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break, | 1345 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break, |
1322 | &data_version, scb); | 1346 | &data_version, scb); |
1347 | afs_update_dentry_version(&fc, dentry, scb); | ||
1323 | ret = afs_end_vnode_operation(&fc); | 1348 | ret = afs_end_vnode_operation(&fc); |
1324 | if (ret == 0) { | 1349 | if (ret == 0) { |
1325 | afs_dir_remove_subdir(dentry); | 1350 | afs_dir_remove_subdir(dentry); |
@@ -1459,6 +1484,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) | |||
1459 | &data_version, &scb[0]); | 1484 | &data_version, &scb[0]); |
1460 | afs_vnode_commit_status(&fc, vnode, fc.cb_break_2, | 1485 | afs_vnode_commit_status(&fc, vnode, fc.cb_break_2, |
1461 | &data_version_2, &scb[1]); | 1486 | &data_version_2, &scb[1]); |
1487 | afs_update_dentry_version(&fc, dentry, &scb[0]); | ||
1462 | ret = afs_end_vnode_operation(&fc); | 1488 | ret = afs_end_vnode_operation(&fc); |
1463 | if (ret == 0 && !(scb[1].have_status || scb[1].have_error)) | 1489 | if (ret == 0 && !(scb[1].have_status || scb[1].have_error)) |
1464 | ret = afs_dir_remove_link(dvnode, dentry, key); | 1490 | ret = afs_dir_remove_link(dvnode, dentry, key); |
@@ -1527,6 +1553,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
1527 | afs_check_for_remote_deletion(&fc, dvnode); | 1553 | afs_check_for_remote_deletion(&fc, dvnode); |
1528 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break, | 1554 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break, |
1529 | &data_version, &scb[0]); | 1555 | &data_version, &scb[0]); |
1556 | afs_update_dentry_version(&fc, dentry, &scb[0]); | ||
1530 | afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); | 1557 | afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); |
1531 | ret = afs_end_vnode_operation(&fc); | 1558 | ret = afs_end_vnode_operation(&fc); |
1532 | if (ret < 0) | 1559 | if (ret < 0) |
@@ -1608,6 +1635,7 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
1608 | afs_vnode_commit_status(&fc, vnode, fc.cb_break_2, | 1635 | afs_vnode_commit_status(&fc, vnode, fc.cb_break_2, |
1609 | NULL, &scb[1]); | 1636 | NULL, &scb[1]); |
1610 | ihold(&vnode->vfs_inode); | 1637 | ihold(&vnode->vfs_inode); |
1638 | afs_update_dentry_version(&fc, dentry, &scb[0]); | ||
1611 | d_instantiate(dentry, &vnode->vfs_inode); | 1639 | d_instantiate(dentry, &vnode->vfs_inode); |
1612 | 1640 | ||
1613 | mutex_unlock(&vnode->io_lock); | 1641 | mutex_unlock(&vnode->io_lock); |
@@ -1687,6 +1715,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
1687 | afs_check_for_remote_deletion(&fc, dvnode); | 1715 | afs_check_for_remote_deletion(&fc, dvnode); |
1688 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break, | 1716 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break, |
1689 | &data_version, &scb[0]); | 1717 | &data_version, &scb[0]); |
1718 | afs_update_dentry_version(&fc, dentry, &scb[0]); | ||
1690 | afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); | 1719 | afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); |
1691 | ret = afs_end_vnode_operation(&fc); | 1720 | ret = afs_end_vnode_operation(&fc); |
1692 | if (ret < 0) | 1721 | if (ret < 0) |
@@ -1792,6 +1821,17 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1792 | } | 1821 | } |
1793 | } | 1822 | } |
1794 | 1823 | ||
1824 | /* This bit is potentially nasty as there's a potential race with | ||
1825 | * afs_d_revalidate{,_rcu}(). We have to change d_fsdata on the dentry | ||
1826 | * to reflect it's new parent's new data_version after the op, but | ||
1827 | * d_revalidate may see old_dentry between the op having taken place | ||
1828 | * and the version being updated. | ||
1829 | * | ||
1830 | * So drop the old_dentry for now to make other threads go through | ||
1831 | * lookup instead - which we hold a lock against. | ||
1832 | */ | ||
1833 | d_drop(old_dentry); | ||
1834 | |||
1795 | ret = -ERESTARTSYS; | 1835 | ret = -ERESTARTSYS; |
1796 | if (afs_begin_vnode_operation(&fc, orig_dvnode, key, true)) { | 1836 | if (afs_begin_vnode_operation(&fc, orig_dvnode, key, true)) { |
1797 | afs_dataversion_t orig_data_version; | 1837 | afs_dataversion_t orig_data_version; |
@@ -1803,7 +1843,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1803 | if (orig_dvnode != new_dvnode) { | 1843 | if (orig_dvnode != new_dvnode) { |
1804 | if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) { | 1844 | if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) { |
1805 | afs_end_vnode_operation(&fc); | 1845 | afs_end_vnode_operation(&fc); |
1806 | goto error_rehash; | 1846 | goto error_rehash_old; |
1807 | } | 1847 | } |
1808 | new_data_version = new_dvnode->status.data_version + 1; | 1848 | new_data_version = new_dvnode->status.data_version + 1; |
1809 | } else { | 1849 | } else { |
@@ -1828,7 +1868,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1828 | } | 1868 | } |
1829 | ret = afs_end_vnode_operation(&fc); | 1869 | ret = afs_end_vnode_operation(&fc); |
1830 | if (ret < 0) | 1870 | if (ret < 0) |
1831 | goto error_rehash; | 1871 | goto error_rehash_old; |
1832 | } | 1872 | } |
1833 | 1873 | ||
1834 | if (ret == 0) { | 1874 | if (ret == 0) { |
@@ -1854,10 +1894,26 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1854 | drop_nlink(new_inode); | 1894 | drop_nlink(new_inode); |
1855 | spin_unlock(&new_inode->i_lock); | 1895 | spin_unlock(&new_inode->i_lock); |
1856 | } | 1896 | } |
1897 | |||
1898 | /* Now we can update d_fsdata on the dentries to reflect their | ||
1899 | * new parent's data_version. | ||
1900 | * | ||
1901 | * Note that if we ever implement RENAME_EXCHANGE, we'll have | ||
1902 | * to update both dentries with opposing dir versions. | ||
1903 | */ | ||
1904 | if (new_dvnode != orig_dvnode) { | ||
1905 | afs_update_dentry_version(&fc, old_dentry, &scb[1]); | ||
1906 | afs_update_dentry_version(&fc, new_dentry, &scb[1]); | ||
1907 | } else { | ||
1908 | afs_update_dentry_version(&fc, old_dentry, &scb[0]); | ||
1909 | afs_update_dentry_version(&fc, new_dentry, &scb[0]); | ||
1910 | } | ||
1857 | d_move(old_dentry, new_dentry); | 1911 | d_move(old_dentry, new_dentry); |
1858 | goto error_tmp; | 1912 | goto error_tmp; |
1859 | } | 1913 | } |
1860 | 1914 | ||
1915 | error_rehash_old: | ||
1916 | d_rehash(new_dentry); | ||
1861 | error_rehash: | 1917 | error_rehash: |
1862 | if (rehash) | 1918 | if (rehash) |
1863 | d_rehash(rehash); | 1919 | d_rehash(rehash); |