summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-04-06 09:17:25 -0400
committerDavid Howells <dhowells@redhat.com>2018-04-09 16:54:48 -0400
commit63a4681ff39cb63314b8ff41319e70fb0e606ed2 (patch)
tree0b60198db6c9a21efd1f1dfda2a292ad63df38e8
parent0031763698d197d779fcafe5685f6e7818b70d32 (diff)
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 <dhowells@redhat.com>
-rw-r--r--fs/afs/Makefile1
-rw-r--r--fs/afs/dir.c83
-rw-r--r--fs/afs/dir_edit.c505
-rw-r--r--fs/afs/fsclient.c35
-rw-r--r--fs/afs/inode.c7
-rw-r--r--fs/afs/internal.h19
-rw-r--r--fs/afs/proc.c4
-rw-r--r--include/trace/events/afs.h90
8 files changed, 715 insertions, 29 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index 6a055423c192..532acae25453 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -12,6 +12,7 @@ kafs-objs := \
12 cell.o \ 12 cell.o \
13 cmservice.o \ 13 cmservice.o \
14 dir.o \ 14 dir.o \
15 dir_edit.o \
15 dynroot.o \ 16 dynroot.o \
16 file.o \ 17 file.o \
17 flock.o \ 18 flock.o \
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index f078ae63d870..43bb3b23a879 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -130,17 +130,26 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page,
130 qty /= sizeof(union afs_xdr_dir_block); 130 qty /= sizeof(union afs_xdr_dir_block);
131 131
132 /* check them */ 132 /* check them */
133 dbuf = page_address(page); 133 dbuf = kmap(page);
134 for (tmp = 0; tmp < qty; tmp++) { 134 for (tmp = 0; tmp < qty; tmp++) {
135 if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) { 135 if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) {
136 printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n", 136 printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n",
137 __func__, dvnode->vfs_inode.i_ino, tmp, qty, 137 __func__, dvnode->vfs_inode.i_ino, tmp, qty,
138 ntohs(dbuf->blocks[tmp].hdr.magic)); 138 ntohs(dbuf->blocks[tmp].hdr.magic));
139 trace_afs_dir_check_failed(dvnode, off, i_size); 139 trace_afs_dir_check_failed(dvnode, off, i_size);
140 kunmap(page);
140 goto error; 141 goto error;
141 } 142 }
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;
142 } 149 }
143 150
151 kunmap(page);
152
144checked: 153checked:
145 afs_stat_v(dvnode, n_read_dir); 154 afs_stat_v(dvnode, n_read_dir);
146 return true; 155 return true;
@@ -1114,6 +1123,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1114 struct afs_vnode *dvnode = AFS_FS_I(dir); 1123 struct afs_vnode *dvnode = AFS_FS_I(dir);
1115 struct afs_fid newfid; 1124 struct afs_fid newfid;
1116 struct key *key; 1125 struct key *key;
1126 u64 data_version = dvnode->status.data_version;
1117 int ret; 1127 int ret;
1118 1128
1119 mode |= S_IFDIR; 1129 mode |= S_IFDIR;
@@ -1131,7 +1141,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1131 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1141 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1132 while (afs_select_fileserver(&fc)) { 1142 while (afs_select_fileserver(&fc)) {
1133 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1143 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,
1135 &newfid, &newstatus, &newcb); 1145 &newfid, &newstatus, &newcb);
1136 } 1146 }
1137 1147
@@ -1145,6 +1155,11 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1145 goto error_key; 1155 goto error_key;
1146 } 1156 }
1147 1157
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
1148 key_put(key); 1163 key_put(key);
1149 _leave(" = 0"); 1164 _leave(" = 0");
1150 return 0; 1165 return 0;
@@ -1168,6 +1183,7 @@ static void afs_dir_remove_subdir(struct dentry *dentry)
1168 clear_nlink(&vnode->vfs_inode); 1183 clear_nlink(&vnode->vfs_inode);
1169 set_bit(AFS_VNODE_DELETED, &vnode->flags); 1184 set_bit(AFS_VNODE_DELETED, &vnode->flags);
1170 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 1185 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
1186 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
1171 } 1187 }
1172} 1188}
1173 1189
@@ -1179,6 +1195,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
1179 struct afs_fs_cursor fc; 1195 struct afs_fs_cursor fc;
1180 struct afs_vnode *dvnode = AFS_FS_I(dir); 1196 struct afs_vnode *dvnode = AFS_FS_I(dir);
1181 struct key *key; 1197 struct key *key;
1198 u64 data_version = dvnode->status.data_version;
1182 int ret; 1199 int ret;
1183 1200
1184 _enter("{%x:%u},{%pd}", 1201 _enter("{%x:%u},{%pd}",
@@ -1194,13 +1211,18 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
1194 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1211 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1195 while (afs_select_fileserver(&fc)) { 1212 while (afs_select_fileserver(&fc)) {
1196 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1213 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);
1198 } 1216 }
1199 1217
1200 afs_vnode_commit_status(&fc, dvnode, fc.cb_break); 1218 afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
1201 ret = afs_end_vnode_operation(&fc); 1219 ret = afs_end_vnode_operation(&fc);
1202 if (ret == 0) 1220 if (ret == 0) {
1203 afs_dir_remove_subdir(dentry); 1221 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 }
1204 } 1226 }
1205 1227
1206 key_put(key); 1228 key_put(key);
@@ -1265,6 +1287,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1265 struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; 1287 struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
1266 struct key *key; 1288 struct key *key;
1267 unsigned long d_version = (unsigned long)dentry->d_fsdata; 1289 unsigned long d_version = (unsigned long)dentry->d_fsdata;
1290 u64 data_version = dvnode->status.data_version;
1268 int ret; 1291 int ret;
1269 1292
1270 _enter("{%x:%u},{%pd}", 1293 _enter("{%x:%u},{%pd}",
@@ -1291,7 +1314,8 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1291 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1314 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1292 while (afs_select_fileserver(&fc)) { 1315 while (afs_select_fileserver(&fc)) {
1293 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1316 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);
1295 } 1319 }
1296 1320
1297 afs_vnode_commit_status(&fc, dvnode, fc.cb_break); 1321 afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
@@ -1300,6 +1324,10 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1300 ret = afs_dir_remove_link( 1324 ret = afs_dir_remove_link(
1301 dentry, key, d_version, 1325 dentry, key, d_version,
1302 (unsigned long)dvnode->status.data_version); 1326 (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);
1303 } 1331 }
1304 1332
1305error_key: 1333error_key:
@@ -1321,6 +1349,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
1321 struct afs_vnode *dvnode = AFS_FS_I(dir); 1349 struct afs_vnode *dvnode = AFS_FS_I(dir);
1322 struct afs_fid newfid; 1350 struct afs_fid newfid;
1323 struct key *key; 1351 struct key *key;
1352 u64 data_version = dvnode->status.data_version;
1324 int ret; 1353 int ret;
1325 1354
1326 mode |= S_IFREG; 1355 mode |= S_IFREG;
@@ -1342,7 +1371,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
1342 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1371 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1343 while (afs_select_fileserver(&fc)) { 1372 while (afs_select_fileserver(&fc)) {
1344 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1373 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,
1346 &newfid, &newstatus, &newcb); 1375 &newfid, &newstatus, &newcb);
1347 } 1376 }
1348 1377
@@ -1356,6 +1385,10 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
1356 goto error_key; 1385 goto error_key;
1357 } 1386 }
1358 1387
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
1359 key_put(key); 1392 key_put(key);
1360 _leave(" = 0"); 1393 _leave(" = 0");
1361 return 0; 1394 return 0;
@@ -1377,10 +1410,12 @@ static int afs_link(struct dentry *from, struct inode *dir,
1377 struct afs_fs_cursor fc; 1410 struct afs_fs_cursor fc;
1378 struct afs_vnode *dvnode, *vnode; 1411 struct afs_vnode *dvnode, *vnode;
1379 struct key *key; 1412 struct key *key;
1413 u64 data_version;
1380 int ret; 1414 int ret;
1381 1415
1382 vnode = AFS_FS_I(d_inode(from)); 1416 vnode = AFS_FS_I(d_inode(from));
1383 dvnode = AFS_FS_I(dir); 1417 dvnode = AFS_FS_I(dir);
1418 data_version = dvnode->status.data_version;
1384 1419
1385 _enter("{%x:%u},{%x:%u},{%pd}", 1420 _enter("{%x:%u},{%x:%u},{%pd}",
1386 vnode->fid.vid, vnode->fid.vnode, 1421 vnode->fid.vid, vnode->fid.vnode,
@@ -1407,7 +1442,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
1407 while (afs_select_fileserver(&fc)) { 1442 while (afs_select_fileserver(&fc)) {
1408 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1443 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1409 fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break; 1444 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);
1411 } 1446 }
1412 1447
1413 afs_vnode_commit_status(&fc, dvnode, fc.cb_break); 1448 afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
@@ -1423,6 +1458,10 @@ static int afs_link(struct dentry *from, struct inode *dir,
1423 goto error_key; 1458 goto error_key;
1424 } 1459 }
1425 1460
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
1426 key_put(key); 1465 key_put(key);
1427 _leave(" = 0"); 1466 _leave(" = 0");
1428 return 0; 1467 return 0;
@@ -1446,6 +1485,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
1446 struct afs_vnode *dvnode = AFS_FS_I(dir); 1485 struct afs_vnode *dvnode = AFS_FS_I(dir);
1447 struct afs_fid newfid; 1486 struct afs_fid newfid;
1448 struct key *key; 1487 struct key *key;
1488 u64 data_version = dvnode->status.data_version;
1449 int ret; 1489 int ret;
1450 1490
1451 _enter("{%x:%u},{%pd},%s", 1491 _enter("{%x:%u},{%pd},%s",
@@ -1470,7 +1510,8 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
1470 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1510 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1471 while (afs_select_fileserver(&fc)) { 1511 while (afs_select_fileserver(&fc)) {
1472 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1512 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,
1474 &newfid, &newstatus); 1515 &newfid, &newstatus);
1475 } 1516 }
1476 1517
@@ -1484,6 +1525,10 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
1484 goto error_key; 1525 goto error_key;
1485 } 1526 }
1486 1527
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
1487 key_put(key); 1532 key_put(key);
1488 _leave(" = 0"); 1533 _leave(" = 0");
1489 return 0; 1534 return 0;
@@ -1506,6 +1551,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1506 struct afs_fs_cursor fc; 1551 struct afs_fs_cursor fc;
1507 struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; 1552 struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
1508 struct key *key; 1553 struct key *key;
1554 u64 orig_data_version, new_data_version;
1555 bool new_negative = d_is_negative(new_dentry);
1509 int ret; 1556 int ret;
1510 1557
1511 if (flags) 1558 if (flags)
@@ -1514,6 +1561,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1514 vnode = AFS_FS_I(d_inode(old_dentry)); 1561 vnode = AFS_FS_I(d_inode(old_dentry));
1515 orig_dvnode = AFS_FS_I(old_dir); 1562 orig_dvnode = AFS_FS_I(old_dir);
1516 new_dvnode = AFS_FS_I(new_dir); 1563 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;
1517 1566
1518 _enter("{%x:%u},{%x:%u},{%x:%u},{%pd}", 1567 _enter("{%x:%u},{%x:%u},{%x:%u},{%pd}",
1519 orig_dvnode->fid.vid, orig_dvnode->fid.vnode, 1568 orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
@@ -1539,7 +1588,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1539 fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break; 1588 fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break;
1540 fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break; 1589 fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break;
1541 afs_fs_rename(&fc, old_dentry->d_name.name, 1590 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);
1543 } 1593 }
1544 1594
1545 afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break); 1595 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,
1551 goto error_key; 1601 goto error_key;
1552 } 1602 }
1553 1603
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
1554error_key: 1619error_key:
1555 key_put(key); 1620 key_put(key);
1556error: 1621error:
diff --git a/fs/afs/dir_edit.c b/fs/afs/dir_edit.c
new file mode 100644
index 000000000000..8b400f5aead5
--- /dev/null
+++ b/fs/afs/dir_edit.c
@@ -0,0 +1,505 @@
1/* AFS filesystem directory editing
2 *
3 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/fs.h>
14#include <linux/namei.h>
15#include <linux/pagemap.h>
16#include <linux/iversion.h>
17#include "internal.h"
18#include "xdr_fs.h"
19
20/*
21 * Find a number of contiguous clear bits in a directory block bitmask.
22 *
23 * There are 64 slots, which means we can load the entire bitmap into a
24 * variable. The first bit doesn't count as it corresponds to the block header
25 * slot. nr_slots is between 1 and 9.
26 */
27static int afs_find_contig_bits(union afs_xdr_dir_block *block, unsigned int nr_slots)
28{
29 u64 bitmap;
30 u32 mask;
31 int bit, n;
32
33 bitmap = (u64)block->hdr.bitmap[0] << 0 * 8;
34 bitmap |= (u64)block->hdr.bitmap[1] << 1 * 8;
35 bitmap |= (u64)block->hdr.bitmap[2] << 2 * 8;
36 bitmap |= (u64)block->hdr.bitmap[3] << 3 * 8;
37 bitmap |= (u64)block->hdr.bitmap[4] << 4 * 8;
38 bitmap |= (u64)block->hdr.bitmap[5] << 5 * 8;
39 bitmap |= (u64)block->hdr.bitmap[6] << 6 * 8;
40 bitmap |= (u64)block->hdr.bitmap[7] << 7 * 8;
41 bitmap >>= 1; /* The first entry is metadata */
42 bit = 1;
43 mask = (1 << nr_slots) - 1;
44
45 do {
46 if (sizeof(unsigned long) == 8)
47 n = ffz(bitmap);
48 else
49 n = ((u32)bitmap) != 0 ?
50 ffz((u32)bitmap) :
51 ffz((u32)(bitmap >> 32)) + 32;
52 bitmap >>= n;
53 bit += n;
54
55 if ((bitmap & mask) == 0) {
56 if (bit > 64 - nr_slots)
57 return -1;
58 return bit;
59 }
60
61 n = __ffs(bitmap);
62 bitmap >>= n;
63 bit += n;
64 } while (bitmap);
65
66 return -1;
67}
68
69/*
70 * Set a number of contiguous bits in the directory block bitmap.
71 */
72static void afs_set_contig_bits(union afs_xdr_dir_block *block,
73 int bit, unsigned int nr_slots)
74{
75 u64 mask, before, after;
76
77 mask = (1 << nr_slots) - 1;
78 mask <<= bit;
79
80 before = *(u64 *)block->hdr.bitmap;
81
82 block->hdr.bitmap[0] |= (u8)(mask >> 0 * 8);
83 block->hdr.bitmap[1] |= (u8)(mask >> 1 * 8);
84 block->hdr.bitmap[2] |= (u8)(mask >> 2 * 8);
85 block->hdr.bitmap[3] |= (u8)(mask >> 3 * 8);
86 block->hdr.bitmap[4] |= (u8)(mask >> 4 * 8);
87 block->hdr.bitmap[5] |= (u8)(mask >> 5 * 8);
88 block->hdr.bitmap[6] |= (u8)(mask >> 6 * 8);
89 block->hdr.bitmap[7] |= (u8)(mask >> 7 * 8);
90
91 after = *(u64 *)block->hdr.bitmap;
92}
93
94/*
95 * Clear a number of contiguous bits in the directory block bitmap.
96 */
97static void afs_clear_contig_bits(union afs_xdr_dir_block *block,
98 int bit, unsigned int nr_slots)
99{
100 u64 mask, before, after;
101
102 mask = (1 << nr_slots) - 1;
103 mask <<= bit;
104
105 before = *(u64 *)block->hdr.bitmap;
106
107 block->hdr.bitmap[0] &= ~(u8)(mask >> 0 * 8);
108 block->hdr.bitmap[1] &= ~(u8)(mask >> 1 * 8);
109 block->hdr.bitmap[2] &= ~(u8)(mask >> 2 * 8);
110 block->hdr.bitmap[3] &= ~(u8)(mask >> 3 * 8);
111 block->hdr.bitmap[4] &= ~(u8)(mask >> 4 * 8);
112 block->hdr.bitmap[5] &= ~(u8)(mask >> 5 * 8);
113 block->hdr.bitmap[6] &= ~(u8)(mask >> 6 * 8);
114 block->hdr.bitmap[7] &= ~(u8)(mask >> 7 * 8);
115
116 after = *(u64 *)block->hdr.bitmap;
117}
118
119/*
120 * Scan a directory block looking for a dirent of the right name.
121 */
122static int afs_dir_scan_block(union afs_xdr_dir_block *block, struct qstr *name,
123 unsigned int blocknum)
124{
125 union afs_xdr_dirent *de;
126 u64 bitmap;
127 int d, len, n;
128
129 _enter("");
130
131 bitmap = (u64)block->hdr.bitmap[0] << 0 * 8;
132 bitmap |= (u64)block->hdr.bitmap[1] << 1 * 8;
133 bitmap |= (u64)block->hdr.bitmap[2] << 2 * 8;
134 bitmap |= (u64)block->hdr.bitmap[3] << 3 * 8;
135 bitmap |= (u64)block->hdr.bitmap[4] << 4 * 8;
136 bitmap |= (u64)block->hdr.bitmap[5] << 5 * 8;
137 bitmap |= (u64)block->hdr.bitmap[6] << 6 * 8;
138 bitmap |= (u64)block->hdr.bitmap[7] << 7 * 8;
139
140 for (d = (blocknum == 0 ? AFS_DIR_RESV_BLOCKS0 : AFS_DIR_RESV_BLOCKS);
141 d < AFS_DIR_SLOTS_PER_BLOCK;
142 d++) {
143 if (!((bitmap >> d) & 1))
144 continue;
145 de = &block->dirents[d];
146 if (de->u.valid != 1)
147 continue;
148
149 /* The block was NUL-terminated by afs_dir_check_page(). */
150 len = strlen(de->u.name);
151 if (len == name->len &&
152 memcmp(de->u.name, name->name, name->len) == 0)
153 return d;
154
155 n = round_up(12 + len + 1 + 4, AFS_DIR_DIRENT_SIZE);
156 n /= AFS_DIR_DIRENT_SIZE;
157 d += n - 1;
158 }
159
160 return -1;
161}
162
163/*
164 * Initialise a new directory block. Note that block 0 is special and contains
165 * some extra metadata.
166 */
167static void afs_edit_init_block(union afs_xdr_dir_block *meta,
168 union afs_xdr_dir_block *block, int block_num)
169{
170 memset(block, 0, sizeof(*block));
171 block->hdr.npages = htons(1);
172 block->hdr.magic = AFS_DIR_MAGIC;
173 block->hdr.bitmap[0] = 1;
174
175 if (block_num == 0) {
176 block->hdr.bitmap[0] = 0xff;
177 block->hdr.bitmap[1] = 0x1f;
178 memset(block->meta.alloc_ctrs,
179 AFS_DIR_SLOTS_PER_BLOCK,
180 sizeof(block->meta.alloc_ctrs));
181 meta->meta.alloc_ctrs[0] =
182 AFS_DIR_SLOTS_PER_BLOCK - AFS_DIR_RESV_BLOCKS0;
183 }
184
185 if (block_num < AFS_DIR_BLOCKS_WITH_CTR)
186 meta->meta.alloc_ctrs[block_num] =
187 AFS_DIR_SLOTS_PER_BLOCK - AFS_DIR_RESV_BLOCKS;
188}
189
190/*
191 * Edit a directory's file data to add a new directory entry. Doing this after
192 * create, mkdir, symlink, link or rename if the data version number is
193 * incremented by exactly one avoids the need to re-download the entire
194 * directory contents.
195 *
196 * The caller must hold the inode locked.
197 */
198void afs_edit_dir_add(struct afs_vnode *vnode,
199 struct qstr *name, struct afs_fid *new_fid,
200 enum afs_edit_dir_reason why)
201{
202 union afs_xdr_dir_block *meta, *block;
203 struct afs_xdr_dir_page *meta_page, *dir_page;
204 union afs_xdr_dirent *de;
205 struct page *page0, *page;
206 unsigned int need_slots, nr_blocks, b;
207 pgoff_t index;
208 loff_t i_size;
209 gfp_t gfp;
210 int slot;
211
212 _enter(",,{%d,%s},", name->len, name->name);
213
214 i_size = i_size_read(&vnode->vfs_inode);
215 if (i_size > AFS_DIR_BLOCK_SIZE * AFS_DIR_MAX_BLOCKS ||
216 (i_size & (AFS_DIR_BLOCK_SIZE - 1))) {
217 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
218 return;
219 }
220
221 gfp = vnode->vfs_inode.i_mapping->gfp_mask;
222 page0 = find_or_create_page(vnode->vfs_inode.i_mapping, 0, gfp);
223 if (!page0) {
224 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
225 _leave(" [fgp]");
226 return;
227 }
228
229 /* Work out how many slots we're going to need. */
230 need_slots = round_up(12 + name->len + 1 + 4, AFS_DIR_DIRENT_SIZE);
231 need_slots /= AFS_DIR_DIRENT_SIZE;
232
233 meta_page = kmap(page0);
234 meta = &meta_page->blocks[0];
235 if (i_size == 0)
236 goto new_directory;
237 nr_blocks = i_size / AFS_DIR_BLOCK_SIZE;
238
239 /* Find a block that has sufficient slots available. Each VM page
240 * contains two or more directory blocks.
241 */
242 for (b = 0; b < nr_blocks + 1; b++) {
243 /* If the directory extended into a new page, then we need to
244 * tack a new page on the end.
245 */
246 index = b / AFS_DIR_BLOCKS_PER_PAGE;
247 if (index == 0) {
248 page = page0;
249 dir_page = meta_page;
250 } else {
251 if (nr_blocks >= AFS_DIR_MAX_BLOCKS)
252 goto error;
253 gfp = vnode->vfs_inode.i_mapping->gfp_mask;
254 page = find_or_create_page(vnode->vfs_inode.i_mapping,
255 index, gfp);
256 if (!page)
257 goto error;
258 if (!PagePrivate(page)) {
259 set_page_private(page, 1);
260 SetPagePrivate(page);
261 }
262 dir_page = kmap(page);
263 }
264
265 /* Abandon the edit if we got a callback break. */
266 if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
267 goto invalidated;
268
269 block = &dir_page->blocks[b % AFS_DIR_BLOCKS_PER_PAGE];
270
271 _debug("block %u: %2u %3u %u",
272 b,
273 (b < AFS_DIR_BLOCKS_WITH_CTR) ? meta->meta.alloc_ctrs[b] : 99,
274 ntohs(block->hdr.npages),
275 ntohs(block->hdr.magic));
276
277 /* Initialise the block if necessary. */
278 if (b == nr_blocks) {
279 _debug("init %u", b);
280 afs_edit_init_block(meta, block, b);
281 i_size_write(&vnode->vfs_inode, (b + 1) * AFS_DIR_BLOCK_SIZE);
282 }
283
284 /* Only lower dir pages have a counter in the header. */
285 if (b >= AFS_DIR_BLOCKS_WITH_CTR ||
286 meta->meta.alloc_ctrs[b] >= need_slots) {
287 /* We need to try and find one or more consecutive
288 * slots to hold the entry.
289 */
290 slot = afs_find_contig_bits(block, need_slots);
291 if (slot >= 0) {
292 _debug("slot %u", slot);
293 goto found_space;
294 }
295 }
296
297 if (page != page0) {
298 unlock_page(page);
299 kunmap(page);
300 put_page(page);
301 }
302 }
303
304 /* There are no spare slots of sufficient size, yet the operation
305 * succeeded. Download the directory again.
306 */
307 trace_afs_edit_dir(vnode, why, afs_edit_dir_create_nospc, 0, 0, 0, 0, name->name);
308 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
309 goto out_unmap;
310
311new_directory:
312 afs_edit_init_block(meta, meta, 0);
313 i_size = AFS_DIR_BLOCK_SIZE;
314 i_size_write(&vnode->vfs_inode, i_size);
315 slot = AFS_DIR_RESV_BLOCKS0;
316 page = page0;
317 block = meta;
318 nr_blocks = 1;
319 b = 0;
320
321found_space:
322 /* Set the dirent slot. */
323 trace_afs_edit_dir(vnode, why, afs_edit_dir_create, b, slot,
324 new_fid->vnode, new_fid->unique, name->name);
325 de = &block->dirents[slot];
326 de->u.valid = 1;
327 de->u.unused[0] = 0;
328 de->u.hash_next = 0; // TODO: Really need to maintain this
329 de->u.vnode = htonl(new_fid->vnode);
330 de->u.unique = htonl(new_fid->unique);
331 memcpy(de->u.name, name->name, name->len + 1);
332 de->u.name[name->len] = 0;
333
334 /* Adjust the bitmap. */
335 afs_set_contig_bits(block, slot, need_slots);
336 if (page != page0) {
337 unlock_page(page);
338 kunmap(page);
339 put_page(page);
340 }
341
342 /* Adjust the allocation counter. */
343 if (b < AFS_DIR_BLOCKS_WITH_CTR)
344 meta->meta.alloc_ctrs[b] -= need_slots;
345
346 inode_inc_iversion_raw(&vnode->vfs_inode);
347 afs_stat_v(vnode, n_dir_cr);
348 _debug("Insert %s in %u[%u]", name->name, b, slot);
349
350out_unmap:
351 unlock_page(page0);
352 kunmap(page0);
353 put_page(page0);
354 _leave("");
355 return;
356
357invalidated:
358 trace_afs_edit_dir(vnode, why, afs_edit_dir_create_inval, 0, 0, 0, 0, name->name);
359 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
360 if (page != page0) {
361 kunmap(page);
362 put_page(page);
363 }
364 goto out_unmap;
365
366error:
367 trace_afs_edit_dir(vnode, why, afs_edit_dir_create_error, 0, 0, 0, 0, name->name);
368 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
369 goto out_unmap;
370}
371
372/*
373 * Edit a directory's file data to remove a new directory entry. Doing this
374 * after unlink, rmdir or rename if the data version number is incremented by
375 * exactly one avoids the need to re-download the entire directory contents.
376 *
377 * The caller must hold the inode locked.
378 */
379void afs_edit_dir_remove(struct afs_vnode *vnode,
380 struct qstr *name, enum afs_edit_dir_reason why)
381{
382 struct afs_xdr_dir_page *meta_page, *dir_page;
383 union afs_xdr_dir_block *meta, *block;
384 union afs_xdr_dirent *de;
385 struct page *page0, *page;
386 unsigned int need_slots, nr_blocks, b;
387 pgoff_t index;
388 loff_t i_size;
389 int slot;
390
391 _enter(",,{%d,%s},", name->len, name->name);
392
393 i_size = i_size_read(&vnode->vfs_inode);
394 if (i_size < AFS_DIR_BLOCK_SIZE ||
395 i_size > AFS_DIR_BLOCK_SIZE * AFS_DIR_MAX_BLOCKS ||
396 (i_size & (AFS_DIR_BLOCK_SIZE - 1))) {
397 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
398 return;
399 }
400 nr_blocks = i_size / AFS_DIR_BLOCK_SIZE;
401
402 page0 = find_lock_page(vnode->vfs_inode.i_mapping, 0);
403 if (!page0) {
404 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
405 _leave(" [fgp]");
406 return;
407 }
408
409 /* Work out how many slots we're going to discard. */
410 need_slots = round_up(12 + name->len + 1 + 4, AFS_DIR_DIRENT_SIZE);
411 need_slots /= AFS_DIR_DIRENT_SIZE;
412
413 meta_page = kmap(page0);
414 meta = &meta_page->blocks[0];
415
416 /* Find a page that has sufficient slots available. Each VM page
417 * contains two or more directory blocks.
418 */
419 for (b = 0; b < nr_blocks; b++) {
420 index = b / AFS_DIR_BLOCKS_PER_PAGE;
421 if (index != 0) {
422 page = find_lock_page(vnode->vfs_inode.i_mapping, index);
423 if (!page)
424 goto error;
425 dir_page = kmap(page);
426 } else {
427 page = page0;
428 dir_page = meta_page;
429 }
430
431 /* Abandon the edit if we got a callback break. */
432 if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
433 goto invalidated;
434
435 block = &dir_page->blocks[b % AFS_DIR_BLOCKS_PER_PAGE];
436
437 if (b > AFS_DIR_BLOCKS_WITH_CTR ||
438 meta->meta.alloc_ctrs[b] <= AFS_DIR_SLOTS_PER_BLOCK - 1 - need_slots) {
439 slot = afs_dir_scan_block(block, name, b);
440 if (slot >= 0)
441 goto found_dirent;
442 }
443
444 if (page != page0) {
445 unlock_page(page);
446 kunmap(page);
447 put_page(page);
448 }
449 }
450
451 /* Didn't find the dirent to clobber. Download the directory again. */
452 trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_noent,
453 0, 0, 0, 0, name->name);
454 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
455 goto out_unmap;
456
457found_dirent:
458 de = &block->dirents[slot];
459
460 trace_afs_edit_dir(vnode, why, afs_edit_dir_delete, b, slot,
461 ntohl(de->u.vnode), ntohl(de->u.unique),
462 name->name);
463
464 memset(de, 0, sizeof(*de) * need_slots);
465
466 /* Adjust the bitmap. */
467 afs_clear_contig_bits(block, slot, need_slots);
468 if (page != page0) {
469 unlock_page(page);
470 kunmap(page);
471 put_page(page);
472 }
473
474 /* Adjust the allocation counter. */
475 if (b < AFS_DIR_BLOCKS_WITH_CTR)
476 meta->meta.alloc_ctrs[b] += need_slots;
477
478 inode_set_iversion_raw(&vnode->vfs_inode, vnode->status.data_version);
479 afs_stat_v(vnode, n_dir_rm);
480 _debug("Remove %s from %u[%u]", name->name, b, slot);
481
482out_unmap:
483 unlock_page(page0);
484 kunmap(page0);
485 put_page(page0);
486 _leave("");
487 return;
488
489invalidated:
490 trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_inval,
491 0, 0, 0, 0, name->name);
492 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
493 if (page != page0) {
494 unlock_page(page);
495 kunmap(page);
496 put_page(page);
497 }
498 goto out_unmap;
499
500error:
501 trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_error,
502 0, 0, 0, 0, name->name);
503 clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
504 goto out_unmap;
505}
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index b66ff0dc8a5a..20d6304a0d3e 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -107,6 +107,13 @@ void afs_update_inode_from_status(struct afs_vnode *vnode,
107 } else { 107 } else {
108 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 108 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
109 } 109 }
110 } else if (vnode->status.type == AFS_FTYPE_DIR) {
111 /* Expected directory change is handled elsewhere so
112 * that we can locally edit the directory and save on a
113 * download.
114 */
115 if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
116 flags &= ~AFS_VNODE_DATA_CHANGED;
110 } 117 }
111 } 118 }
112 119
@@ -190,10 +197,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
190 197
191 size = (u64)ntohl(xdr->size_lo); 198 size = (u64)ntohl(xdr->size_lo);
192 size |= (u64)ntohl(xdr->size_hi) << 32; 199 size |= (u64)ntohl(xdr->size_hi) << 32;
193 if (size != status->size) { 200 status->size = size;
194 status->size = size;
195 flags |= AFS_VNODE_DATA_CHANGED;
196 }
197 201
198 data_version = (u64)ntohl(xdr->data_version_lo); 202 data_version = (u64)ntohl(xdr->data_version_lo);
199 data_version |= (u64)ntohl(xdr->data_version_hi) << 32; 203 data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
@@ -736,6 +740,7 @@ static const struct afs_call_type afs_RXFSMakeDir = {
736int afs_fs_create(struct afs_fs_cursor *fc, 740int afs_fs_create(struct afs_fs_cursor *fc,
737 const char *name, 741 const char *name,
738 umode_t mode, 742 umode_t mode,
743 u64 current_data_version,
739 struct afs_fid *newfid, 744 struct afs_fid *newfid,
740 struct afs_file_status *newstatus, 745 struct afs_file_status *newstatus,
741 struct afs_callback *newcb) 746 struct afs_callback *newcb)
@@ -763,7 +768,7 @@ int afs_fs_create(struct afs_fs_cursor *fc,
763 call->reply[1] = newfid; 768 call->reply[1] = newfid;
764 call->reply[2] = newstatus; 769 call->reply[2] = newstatus;
765 call->reply[3] = newcb; 770 call->reply[3] = newcb;
766 call->expected_version = vnode->status.data_version; 771 call->expected_version = current_data_version + 1;
767 772
768 /* marshall the parameters */ 773 /* marshall the parameters */
769 bp = call->request; 774 bp = call->request;
@@ -836,7 +841,8 @@ static const struct afs_call_type afs_RXFSRemoveDir = {
836/* 841/*
837 * remove a file or directory 842 * remove a file or directory
838 */ 843 */
839int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir) 844int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir,
845 u64 current_data_version)
840{ 846{
841 struct afs_vnode *vnode = fc->vnode; 847 struct afs_vnode *vnode = fc->vnode;
842 struct afs_call *call; 848 struct afs_call *call;
@@ -858,7 +864,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir)
858 864
859 call->key = fc->key; 865 call->key = fc->key;
860 call->reply[0] = vnode; 866 call->reply[0] = vnode;
861 call->expected_version = vnode->status.data_version; 867 call->expected_version = current_data_version + 1;
862 868
863 /* marshall the parameters */ 869 /* marshall the parameters */
864 bp = call->request; 870 bp = call->request;
@@ -920,7 +926,7 @@ static const struct afs_call_type afs_RXFSLink = {
920 * make a hard link 926 * make a hard link
921 */ 927 */
922int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, 928int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
923 const char *name) 929 const char *name, u64 current_data_version)
924{ 930{
925 struct afs_vnode *dvnode = fc->vnode; 931 struct afs_vnode *dvnode = fc->vnode;
926 struct afs_call *call; 932 struct afs_call *call;
@@ -941,7 +947,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
941 call->key = fc->key; 947 call->key = fc->key;
942 call->reply[0] = dvnode; 948 call->reply[0] = dvnode;
943 call->reply[1] = vnode; 949 call->reply[1] = vnode;
944 call->expected_version = vnode->status.data_version; 950 call->expected_version = current_data_version + 1;
945 951
946 /* marshall the parameters */ 952 /* marshall the parameters */
947 bp = call->request; 953 bp = call->request;
@@ -1009,6 +1015,7 @@ static const struct afs_call_type afs_RXFSSymlink = {
1009int afs_fs_symlink(struct afs_fs_cursor *fc, 1015int afs_fs_symlink(struct afs_fs_cursor *fc,
1010 const char *name, 1016 const char *name,
1011 const char *contents, 1017 const char *contents,
1018 u64 current_data_version,
1012 struct afs_fid *newfid, 1019 struct afs_fid *newfid,
1013 struct afs_file_status *newstatus) 1020 struct afs_file_status *newstatus)
1014{ 1021{
@@ -1037,7 +1044,7 @@ int afs_fs_symlink(struct afs_fs_cursor *fc,
1037 call->reply[0] = vnode; 1044 call->reply[0] = vnode;
1038 call->reply[1] = newfid; 1045 call->reply[1] = newfid;
1039 call->reply[2] = newstatus; 1046 call->reply[2] = newstatus;
1040 call->expected_version = vnode->status.data_version; 1047 call->expected_version = current_data_version + 1;
1041 1048
1042 /* marshall the parameters */ 1049 /* marshall the parameters */
1043 bp = call->request; 1050 bp = call->request;
@@ -1117,7 +1124,9 @@ static const struct afs_call_type afs_RXFSRename = {
1117int afs_fs_rename(struct afs_fs_cursor *fc, 1124int afs_fs_rename(struct afs_fs_cursor *fc,
1118 const char *orig_name, 1125 const char *orig_name,
1119 struct afs_vnode *new_dvnode, 1126 struct afs_vnode *new_dvnode,
1120 const char *new_name) 1127 const char *new_name,
1128 u64 current_orig_data_version,
1129 u64 current_new_data_version)
1121{ 1130{
1122 struct afs_vnode *orig_dvnode = fc->vnode; 1131 struct afs_vnode *orig_dvnode = fc->vnode;
1123 struct afs_call *call; 1132 struct afs_call *call;
@@ -1145,8 +1154,8 @@ int afs_fs_rename(struct afs_fs_cursor *fc,
1145 call->key = fc->key; 1154 call->key = fc->key;
1146 call->reply[0] = orig_dvnode; 1155 call->reply[0] = orig_dvnode;
1147 call->reply[1] = new_dvnode; 1156 call->reply[1] = new_dvnode;
1148 call->expected_version = orig_dvnode->status.data_version; 1157 call->expected_version = current_orig_data_version + 1;
1149 call->expected_version_2 = new_dvnode->status.data_version; 1158 call->expected_version_2 = current_new_data_version + 1;
1150 1159
1151 /* marshall the parameters */ 1160 /* marshall the parameters */
1152 bp = call->request; 1161 bp = call->request;
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 69bcfb82dd69..3808dcbbac6d 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -395,8 +395,11 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
395 if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 395 if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
396 if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) { 396 if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) {
397 vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; 397 vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
398 } else if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) && 398 } else if (vnode->status.type == AFS_FTYPE_DIR &&
399 !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && 399 test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) &&
400 vnode->cb_expires_at - 10 > now) {
401 valid = true;
402 } else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
400 vnode->cb_expires_at - 10 > now) { 403 vnode->cb_expires_at - 10 > now) {
401 valid = true; 404 valid = true;
402 } 405 }
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 86f3066d9ab0..703ddb8c5d57 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -271,6 +271,8 @@ struct afs_net {
271 atomic_t n_inval; /* Number of invalidations by the server */ 271 atomic_t n_inval; /* Number of invalidations by the server */
272 atomic_t n_relpg; /* Number of invalidations by releasepage */ 272 atomic_t n_relpg; /* Number of invalidations by releasepage */
273 atomic_t n_read_dir; /* Number of directory pages read */ 273 atomic_t n_read_dir; /* Number of directory pages read */
274 atomic_t n_dir_cr; /* Number of directory entry creation edits */
275 atomic_t n_dir_rm; /* Number of directory entry removal edits */
274}; 276};
275 277
276extern const char afs_init_sysname[]; 278extern const char afs_init_sysname[];
@@ -680,6 +682,13 @@ extern const struct dentry_operations afs_fs_dentry_operations;
680extern void afs_d_release(struct dentry *); 682extern void afs_d_release(struct dentry *);
681 683
682/* 684/*
685 * dir_edit.c
686 */
687extern void afs_edit_dir_add(struct afs_vnode *, struct qstr *, struct afs_fid *,
688 enum afs_edit_dir_reason);
689extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, enum afs_edit_dir_reason);
690
691/*
683 * dynroot.c 692 * dynroot.c
684 */ 693 */
685extern const struct file_operations afs_dynroot_file_operations; 694extern const struct file_operations afs_dynroot_file_operations;
@@ -725,14 +734,14 @@ extern void afs_update_inode_from_status(struct afs_vnode *, struct afs_file_sta
725extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool); 734extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool);
726extern int afs_fs_give_up_callbacks(struct afs_net *, struct afs_server *); 735extern int afs_fs_give_up_callbacks(struct afs_net *, struct afs_server *);
727extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *); 736extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *);
728extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, 737extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, u64,
729 struct afs_fid *, struct afs_file_status *, struct afs_callback *); 738 struct afs_fid *, struct afs_file_status *, struct afs_callback *);
730extern int afs_fs_remove(struct afs_fs_cursor *, const char *, bool); 739extern int afs_fs_remove(struct afs_fs_cursor *, const char *, bool, u64);
731extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *); 740extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64);
732extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, 741extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64,
733 struct afs_fid *, struct afs_file_status *); 742 struct afs_fid *, struct afs_file_status *);
734extern int afs_fs_rename(struct afs_fs_cursor *, const char *, 743extern int afs_fs_rename(struct afs_fs_cursor *, const char *,
735 struct afs_vnode *, const char *); 744 struct afs_vnode *, const char *, u64, u64);
736extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *, 745extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *,
737 pgoff_t, pgoff_t, unsigned, unsigned); 746 pgoff_t, pgoff_t, unsigned, unsigned);
738extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *); 747extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *);
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 6f5a000f44a7..3212bce0d4fb 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -918,6 +918,10 @@ static int afs_proc_stats_show(struct seq_file *m, void *v)
918 918
919 seq_printf(m, "dir-data: rdpg=%u\n", 919 seq_printf(m, "dir-data: rdpg=%u\n",
920 atomic_read(&net->n_read_dir)); 920 atomic_read(&net->n_read_dir));
921
922 seq_printf(m, "dir-edit: cr=%u rm=%u\n",
923 atomic_read(&net->n_dir_cr),
924 atomic_read(&net->n_dir_rm));
921 return 0; 925 return 0;
922} 926}
923 927
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 0419b7e1e968..f46dee0f5ced 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -63,6 +63,27 @@ enum afs_vl_operation {
63 afs_VL_GetCapabilities = 65537, /* AFS Get VL server capabilities */ 63 afs_VL_GetCapabilities = 65537, /* AFS Get VL server capabilities */
64}; 64};
65 65
66enum afs_edit_dir_op {
67 afs_edit_dir_create,
68 afs_edit_dir_create_error,
69 afs_edit_dir_create_inval,
70 afs_edit_dir_create_nospc,
71 afs_edit_dir_delete,
72 afs_edit_dir_delete_error,
73 afs_edit_dir_delete_inval,
74 afs_edit_dir_delete_noent,
75};
76
77enum afs_edit_dir_reason {
78 afs_edit_dir_for_create,
79 afs_edit_dir_for_link,
80 afs_edit_dir_for_mkdir,
81 afs_edit_dir_for_rename,
82 afs_edit_dir_for_rmdir,
83 afs_edit_dir_for_symlink,
84 afs_edit_dir_for_unlink,
85};
86
66#endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */ 87#endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */
67 88
68/* 89/*
@@ -106,6 +127,25 @@ enum afs_vl_operation {
106 EM(afs_YFSVL_GetEndpoints, "YFSVL.GetEndpoints") \ 127 EM(afs_YFSVL_GetEndpoints, "YFSVL.GetEndpoints") \
107 E_(afs_VL_GetCapabilities, "VL.GetCapabilities") 128 E_(afs_VL_GetCapabilities, "VL.GetCapabilities")
108 129
130#define afs_edit_dir_ops \
131 EM(afs_edit_dir_create, "create") \
132 EM(afs_edit_dir_create_error, "c_fail") \
133 EM(afs_edit_dir_create_inval, "c_invl") \
134 EM(afs_edit_dir_create_nospc, "c_nspc") \
135 EM(afs_edit_dir_delete, "delete") \
136 EM(afs_edit_dir_delete_error, "d_err ") \
137 EM(afs_edit_dir_delete_inval, "d_invl") \
138 E_(afs_edit_dir_delete_noent, "d_nent")
139
140#define afs_edit_dir_reasons \
141 EM(afs_edit_dir_for_create, "Create") \
142 EM(afs_edit_dir_for_link, "Link ") \
143 EM(afs_edit_dir_for_mkdir, "MkDir ") \
144 EM(afs_edit_dir_for_rename, "Rename") \
145 EM(afs_edit_dir_for_rmdir, "RmDir ") \
146 EM(afs_edit_dir_for_symlink, "Symlnk") \
147 E_(afs_edit_dir_for_unlink, "Unlink")
148
109 149
110/* 150/*
111 * Export enum symbols via userspace. 151 * Export enum symbols via userspace.
@@ -118,6 +158,8 @@ enum afs_vl_operation {
118afs_call_traces; 158afs_call_traces;
119afs_fs_operations; 159afs_fs_operations;
120afs_vl_operations; 160afs_vl_operations;
161afs_edit_dir_ops;
162afs_edit_dir_reasons;
121 163
122/* 164/*
123 * Now redefine the EM() and E_() macros to map the enums to the strings that 165 * Now redefine the EM() and E_() macros to map the enums to the strings that
@@ -464,6 +506,54 @@ TRACE_EVENT(afs_call_state,
464 __entry->ret, __entry->abort) 506 __entry->ret, __entry->abort)
465 ); 507 );
466 508
509TRACE_EVENT(afs_edit_dir,
510 TP_PROTO(struct afs_vnode *dvnode,
511 enum afs_edit_dir_reason why,
512 enum afs_edit_dir_op op,
513 unsigned int block,
514 unsigned int slot,
515 unsigned int f_vnode,
516 unsigned int f_unique,
517 const char *name),
518
519 TP_ARGS(dvnode, why, op, block, slot, f_vnode, f_unique, name),
520
521 TP_STRUCT__entry(
522 __field(unsigned int, vnode )
523 __field(unsigned int, unique )
524 __field(enum afs_edit_dir_reason, why )
525 __field(enum afs_edit_dir_op, op )
526 __field(unsigned int, block )
527 __field(unsigned short, slot )
528 __field(unsigned int, f_vnode )
529 __field(unsigned int, f_unique )
530 __array(char, name, 18 )
531 ),
532
533 TP_fast_assign(
534 int __len = strlen(name);
535 __len = min(__len, 17);
536 __entry->vnode = dvnode->fid.vnode;
537 __entry->unique = dvnode->fid.unique;
538 __entry->why = why;
539 __entry->op = op;
540 __entry->block = block;
541 __entry->slot = slot;
542 __entry->f_vnode = f_vnode;
543 __entry->f_unique = f_unique;
544 memcpy(__entry->name, name, __len);
545 __entry->name[__len] = 0;
546 ),
547
548 TP_printk("d=%x:%x %s %s %u[%u] f=%x:%x %s",
549 __entry->vnode, __entry->unique,
550 __print_symbolic(__entry->why, afs_edit_dir_reasons),
551 __print_symbolic(__entry->op, afs_edit_dir_ops),
552 __entry->block, __entry->slot,
553 __entry->f_vnode, __entry->f_unique,
554 __entry->name)
555 );
556
467#endif /* _TRACE_AFS_H */ 557#endif /* _TRACE_AFS_H */
468 558
469/* This part must be outside protection */ 559/* This part must be outside protection */