Skip to content

Commit 63a4681

Browse files
committed
afs: Locally edit directory data for mkdir/create/unlink/...
Locally edit the contents of an AFS directory upon a successful inode operation that modifies that directory (such as mkdir, create and unlink) so that we can avoid the current practice of re-downloading the directory after each change. This is viable provided that the directory version number we get back from the modifying RPC op is exactly incremented by 1 from what we had previously. The data in the directory contents is in a defined format that we have to parse locally to perform lookups and readdir, so modifying isn't a problem. If the edit fails, we just clear the VALID flag on the directory and it will be reloaded next time it is needed. Signed-off-by: David Howells <[email protected]>
1 parent 0031763 commit 63a4681

File tree

8 files changed

+715
-29
lines changed

8 files changed

+715
-29
lines changed

fs/afs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ kafs-objs := \
1212
cell.o \
1313
cmservice.o \
1414
dir.o \
15+
dir_edit.o \
1516
dynroot.o \
1617
file.o \
1718
flock.o \

fs/afs/dir.c

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,17 +130,26 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page,
130130
qty /= sizeof(union afs_xdr_dir_block);
131131

132132
/* check them */
133-
dbuf = page_address(page);
133+
dbuf = kmap(page);
134134
for (tmp = 0; tmp < qty; tmp++) {
135135
if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) {
136136
printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n",
137137
__func__, dvnode->vfs_inode.i_ino, tmp, qty,
138138
ntohs(dbuf->blocks[tmp].hdr.magic));
139139
trace_afs_dir_check_failed(dvnode, off, i_size);
140+
kunmap(page);
140141
goto error;
141142
}
143+
144+
/* Make sure each block is NUL terminated so we can reasonably
145+
* use string functions on it. The filenames in the page
146+
* *should* be NUL-terminated anyway.
147+
*/
148+
((u8 *)&dbuf->blocks[tmp])[AFS_DIR_BLOCK_SIZE - 1] = 0;
142149
}
143150

151+
kunmap(page);
152+
144153
checked:
145154
afs_stat_v(dvnode, n_read_dir);
146155
return true;
@@ -1114,6 +1123,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
11141123
struct afs_vnode *dvnode = AFS_FS_I(dir);
11151124
struct afs_fid newfid;
11161125
struct key *key;
1126+
u64 data_version = dvnode->status.data_version;
11171127
int ret;
11181128

11191129
mode |= S_IFDIR;
@@ -1131,7 +1141,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
11311141
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
11321142
while (afs_select_fileserver(&fc)) {
11331143
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1134-
afs_fs_create(&fc, dentry->d_name.name, mode,
1144+
afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
11351145
&newfid, &newstatus, &newcb);
11361146
}
11371147

@@ -1145,6 +1155,11 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
11451155
goto error_key;
11461156
}
11471157

1158+
if (ret == 0 &&
1159+
test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
1160+
afs_edit_dir_add(dvnode, &dentry->d_name, &newfid,
1161+
afs_edit_dir_for_create);
1162+
11481163
key_put(key);
11491164
_leave(" = 0");
11501165
return 0;
@@ -1168,6 +1183,7 @@ static void afs_dir_remove_subdir(struct dentry *dentry)
11681183
clear_nlink(&vnode->vfs_inode);
11691184
set_bit(AFS_VNODE_DELETED, &vnode->flags);
11701185
clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
1186+
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
11711187
}
11721188
}
11731189

@@ -1179,6 +1195,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
11791195
struct afs_fs_cursor fc;
11801196
struct afs_vnode *dvnode = AFS_FS_I(dir);
11811197
struct key *key;
1198+
u64 data_version = dvnode->status.data_version;
11821199
int ret;
11831200

11841201
_enter("{%x:%u},{%pd}",
@@ -1194,13 +1211,18 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
11941211
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
11951212
while (afs_select_fileserver(&fc)) {
11961213
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1197-
afs_fs_remove(&fc, dentry->d_name.name, true);
1214+
afs_fs_remove(&fc, dentry->d_name.name, true,
1215+
data_version);
11981216
}
11991217

12001218
afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
12011219
ret = afs_end_vnode_operation(&fc);
1202-
if (ret == 0)
1220+
if (ret == 0) {
12031221
afs_dir_remove_subdir(dentry);
1222+
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
1223+
afs_edit_dir_remove(dvnode, &dentry->d_name,
1224+
afs_edit_dir_for_rmdir);
1225+
}
12041226
}
12051227

12061228
key_put(key);
@@ -1265,6 +1287,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
12651287
struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
12661288
struct key *key;
12671289
unsigned long d_version = (unsigned long)dentry->d_fsdata;
1290+
u64 data_version = dvnode->status.data_version;
12681291
int ret;
12691292

12701293
_enter("{%x:%u},{%pd}",
@@ -1291,7 +1314,8 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
12911314
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
12921315
while (afs_select_fileserver(&fc)) {
12931316
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1294-
afs_fs_remove(&fc, dentry->d_name.name, false);
1317+
afs_fs_remove(&fc, dentry->d_name.name, false,
1318+
data_version);
12951319
}
12961320

12971321
afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
@@ -1300,6 +1324,10 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
13001324
ret = afs_dir_remove_link(
13011325
dentry, key, d_version,
13021326
(unsigned long)dvnode->status.data_version);
1327+
if (ret == 0 &&
1328+
test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
1329+
afs_edit_dir_remove(dvnode, &dentry->d_name,
1330+
afs_edit_dir_for_unlink);
13031331
}
13041332

13051333
error_key:
@@ -1321,6 +1349,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
13211349
struct afs_vnode *dvnode = AFS_FS_I(dir);
13221350
struct afs_fid newfid;
13231351
struct key *key;
1352+
u64 data_version = dvnode->status.data_version;
13241353
int ret;
13251354

13261355
mode |= S_IFREG;
@@ -1342,7 +1371,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
13421371
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
13431372
while (afs_select_fileserver(&fc)) {
13441373
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1345-
afs_fs_create(&fc, dentry->d_name.name, mode,
1374+
afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
13461375
&newfid, &newstatus, &newcb);
13471376
}
13481377

@@ -1356,6 +1385,10 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
13561385
goto error_key;
13571386
}
13581387

1388+
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
1389+
afs_edit_dir_add(dvnode, &dentry->d_name, &newfid,
1390+
afs_edit_dir_for_create);
1391+
13591392
key_put(key);
13601393
_leave(" = 0");
13611394
return 0;
@@ -1377,10 +1410,12 @@ static int afs_link(struct dentry *from, struct inode *dir,
13771410
struct afs_fs_cursor fc;
13781411
struct afs_vnode *dvnode, *vnode;
13791412
struct key *key;
1413+
u64 data_version;
13801414
int ret;
13811415

13821416
vnode = AFS_FS_I(d_inode(from));
13831417
dvnode = AFS_FS_I(dir);
1418+
data_version = dvnode->status.data_version;
13841419

13851420
_enter("{%x:%u},{%x:%u},{%pd}",
13861421
vnode->fid.vid, vnode->fid.vnode,
@@ -1407,7 +1442,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
14071442
while (afs_select_fileserver(&fc)) {
14081443
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
14091444
fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break;
1410-
afs_fs_link(&fc, vnode, dentry->d_name.name);
1445+
afs_fs_link(&fc, vnode, dentry->d_name.name, data_version);
14111446
}
14121447

14131448
afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
@@ -1423,6 +1458,10 @@ static int afs_link(struct dentry *from, struct inode *dir,
14231458
goto error_key;
14241459
}
14251460

1461+
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
1462+
afs_edit_dir_add(dvnode, &dentry->d_name, &vnode->fid,
1463+
afs_edit_dir_for_link);
1464+
14261465
key_put(key);
14271466
_leave(" = 0");
14281467
return 0;
@@ -1446,6 +1485,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
14461485
struct afs_vnode *dvnode = AFS_FS_I(dir);
14471486
struct afs_fid newfid;
14481487
struct key *key;
1488+
u64 data_version = dvnode->status.data_version;
14491489
int ret;
14501490

14511491
_enter("{%x:%u},{%pd},%s",
@@ -1470,7 +1510,8 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
14701510
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
14711511
while (afs_select_fileserver(&fc)) {
14721512
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1473-
afs_fs_symlink(&fc, dentry->d_name.name, content,
1513+
afs_fs_symlink(&fc, dentry->d_name.name,
1514+
content, data_version,
14741515
&newfid, &newstatus);
14751516
}
14761517

@@ -1484,6 +1525,10 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
14841525
goto error_key;
14851526
}
14861527

1528+
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
1529+
afs_edit_dir_add(dvnode, &dentry->d_name, &newfid,
1530+
afs_edit_dir_for_symlink);
1531+
14871532
key_put(key);
14881533
_leave(" = 0");
14891534
return 0;
@@ -1506,6 +1551,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
15061551
struct afs_fs_cursor fc;
15071552
struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
15081553
struct key *key;
1554+
u64 orig_data_version, new_data_version;
1555+
bool new_negative = d_is_negative(new_dentry);
15091556
int ret;
15101557

15111558
if (flags)
@@ -1514,6 +1561,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
15141561
vnode = AFS_FS_I(d_inode(old_dentry));
15151562
orig_dvnode = AFS_FS_I(old_dir);
15161563
new_dvnode = AFS_FS_I(new_dir);
1564+
orig_data_version = orig_dvnode->status.data_version;
1565+
new_data_version = new_dvnode->status.data_version;
15171566

15181567
_enter("{%x:%u},{%x:%u},{%x:%u},{%pd}",
15191568
orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
@@ -1539,7 +1588,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
15391588
fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break;
15401589
fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break;
15411590
afs_fs_rename(&fc, old_dentry->d_name.name,
1542-
new_dvnode, new_dentry->d_name.name);
1591+
new_dvnode, new_dentry->d_name.name,
1592+
orig_data_version, new_data_version);
15431593
}
15441594

15451595
afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break);
@@ -1551,6 +1601,21 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
15511601
goto error_key;
15521602
}
15531603

1604+
if (ret == 0) {
1605+
if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags))
1606+
afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name,
1607+
afs_edit_dir_for_rename);
1608+
1609+
if (!new_negative &&
1610+
test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
1611+
afs_edit_dir_remove(new_dvnode, &new_dentry->d_name,
1612+
afs_edit_dir_for_rename);
1613+
1614+
if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
1615+
afs_edit_dir_add(new_dvnode, &new_dentry->d_name,
1616+
&vnode->fid, afs_edit_dir_for_rename);
1617+
}
1618+
15541619
error_key:
15551620
key_put(key);
15561621
error:

0 commit comments

Comments
 (0)