Commit 63a4681f authored by David Howells's avatar David Howells

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: default avatarDavid Howells <dhowells@redhat.com>
parent 00317636
...@@ -12,6 +12,7 @@ kafs-objs := \ ...@@ -12,6 +12,7 @@ kafs-objs := \
cell.o \ cell.o \
cmservice.o \ cmservice.o \
dir.o \ dir.o \
dir_edit.o \
dynroot.o \ dynroot.o \
file.o \ file.o \
flock.o \ flock.o \
......
...@@ -130,17 +130,26 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page, ...@@ -130,17 +130,26 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page,
qty /= sizeof(union afs_xdr_dir_block); qty /= sizeof(union afs_xdr_dir_block);
/* check them */ /* check them */
dbuf = page_address(page); dbuf = kmap(page);
for (tmp = 0; tmp < qty; tmp++) { for (tmp = 0; tmp < qty; tmp++) {
if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) { if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) {
printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n", printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n",
__func__, dvnode->vfs_inode.i_ino, tmp, qty, __func__, dvnode->vfs_inode.i_ino, tmp, qty,
ntohs(dbuf->blocks[tmp].hdr.magic)); ntohs(dbuf->blocks[tmp].hdr.magic));
trace_afs_dir_check_failed(dvnode, off, i_size); trace_afs_dir_check_failed(dvnode, off, i_size);
kunmap(page);
goto error; goto error;
} }
/* Make sure each block is NUL terminated so we can reasonably
* use string functions on it. The filenames in the page
* *should* be NUL-terminated anyway.
*/
((u8 *)&dbuf->blocks[tmp])[AFS_DIR_BLOCK_SIZE - 1] = 0;
} }
kunmap(page);
checked: checked:
afs_stat_v(dvnode, n_read_dir); afs_stat_v(dvnode, n_read_dir);
return true; return true;
...@@ -1114,6 +1123,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -1114,6 +1123,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_vnode *dvnode = AFS_FS_I(dir);
struct afs_fid newfid; struct afs_fid newfid;
struct key *key; struct key *key;
u64 data_version = dvnode->status.data_version;
int ret; int ret;
mode |= S_IFDIR; mode |= S_IFDIR;
...@@ -1131,7 +1141,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -1131,7 +1141,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
afs_fs_create(&fc, dentry->d_name.name, mode, afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
&newfid, &newstatus, &newcb); &newfid, &newstatus, &newcb);
} }
...@@ -1145,6 +1155,11 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -1145,6 +1155,11 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
goto error_key; goto error_key;
} }
if (ret == 0 &&
test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
afs_edit_dir_add(dvnode, &dentry->d_name, &newfid,
afs_edit_dir_for_create);
key_put(key); key_put(key);
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
...@@ -1168,6 +1183,7 @@ static void afs_dir_remove_subdir(struct dentry *dentry) ...@@ -1168,6 +1183,7 @@ static void afs_dir_remove_subdir(struct dentry *dentry)
clear_nlink(&vnode->vfs_inode); clear_nlink(&vnode->vfs_inode);
set_bit(AFS_VNODE_DELETED, &vnode->flags); set_bit(AFS_VNODE_DELETED, &vnode->flags);
clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
} }
} }
...@@ -1179,6 +1195,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1179,6 +1195,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_vnode *dvnode = AFS_FS_I(dir);
struct key *key; struct key *key;
u64 data_version = dvnode->status.data_version;
int ret; int ret;
_enter("{%x:%u},{%pd}", _enter("{%x:%u},{%pd}",
...@@ -1194,13 +1211,18 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1194,13 +1211,18 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
afs_fs_remove(&fc, dentry->d_name.name, true); afs_fs_remove(&fc, dentry->d_name.name, true,
data_version);
} }
afs_vnode_commit_status(&fc, dvnode, fc.cb_break); afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
ret = afs_end_vnode_operation(&fc); ret = afs_end_vnode_operation(&fc);
if (ret == 0) if (ret == 0) {
afs_dir_remove_subdir(dentry); afs_dir_remove_subdir(dentry);
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
afs_edit_dir_remove(dvnode, &dentry->d_name,
afs_edit_dir_for_rmdir);
}
} }
key_put(key); key_put(key);
...@@ -1265,6 +1287,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1265,6 +1287,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
struct key *key; struct key *key;
unsigned long d_version = (unsigned long)dentry->d_fsdata; unsigned long d_version = (unsigned long)dentry->d_fsdata;
u64 data_version = dvnode->status.data_version;
int ret; int ret;
_enter("{%x:%u},{%pd}", _enter("{%x:%u},{%pd}",
...@@ -1291,7 +1314,8 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1291,7 +1314,8 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
afs_fs_remove(&fc, dentry->d_name.name, false); afs_fs_remove(&fc, dentry->d_name.name, false,
data_version);
} }
afs_vnode_commit_status(&fc, dvnode, fc.cb_break); afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
...@@ -1300,6 +1324,10 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1300,6 +1324,10 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
ret = afs_dir_remove_link( ret = afs_dir_remove_link(
dentry, key, d_version, dentry, key, d_version,
(unsigned long)dvnode->status.data_version); (unsigned long)dvnode->status.data_version);
if (ret == 0 &&
test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
afs_edit_dir_remove(dvnode, &dentry->d_name,
afs_edit_dir_for_unlink);
} }
error_key: error_key:
...@@ -1321,6 +1349,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -1321,6 +1349,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_vnode *dvnode = AFS_FS_I(dir);
struct afs_fid newfid; struct afs_fid newfid;
struct key *key; struct key *key;
u64 data_version = dvnode->status.data_version;
int ret; int ret;
mode |= S_IFREG; mode |= S_IFREG;
...@@ -1342,7 +1371,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -1342,7 +1371,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
afs_fs_create(&fc, dentry->d_name.name, mode, afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
&newfid, &newstatus, &newcb); &newfid, &newstatus, &newcb);
} }
...@@ -1356,6 +1385,10 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -1356,6 +1385,10 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
goto error_key; goto error_key;
} }
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
afs_edit_dir_add(dvnode, &dentry->d_name, &newfid,
afs_edit_dir_for_create);
key_put(key); key_put(key);
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
...@@ -1377,10 +1410,12 @@ static int afs_link(struct dentry *from, struct inode *dir, ...@@ -1377,10 +1410,12 @@ static int afs_link(struct dentry *from, struct inode *dir,
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
struct afs_vnode *dvnode, *vnode; struct afs_vnode *dvnode, *vnode;
struct key *key; struct key *key;
u64 data_version;
int ret; int ret;
vnode = AFS_FS_I(d_inode(from)); vnode = AFS_FS_I(d_inode(from));
dvnode = AFS_FS_I(dir); dvnode = AFS_FS_I(dir);
data_version = dvnode->status.data_version;
_enter("{%x:%u},{%x:%u},{%pd}", _enter("{%x:%u},{%x:%u},{%pd}",
vnode->fid.vid, vnode->fid.vnode, vnode->fid.vid, vnode->fid.vnode,
...@@ -1407,7 +1442,7 @@ static int afs_link(struct dentry *from, struct inode *dir, ...@@ -1407,7 +1442,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break; fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break;
afs_fs_link(&fc, vnode, dentry->d_name.name); afs_fs_link(&fc, vnode, dentry->d_name.name, data_version);
} }
afs_vnode_commit_status(&fc, dvnode, fc.cb_break); afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
...@@ -1423,6 +1458,10 @@ static int afs_link(struct dentry *from, struct inode *dir, ...@@ -1423,6 +1458,10 @@ static int afs_link(struct dentry *from, struct inode *dir,
goto error_key; goto error_key;
} }
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
afs_edit_dir_add(dvnode, &dentry->d_name, &vnode->fid,
afs_edit_dir_for_link);
key_put(key); key_put(key);
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
...@@ -1446,6 +1485,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1446,6 +1485,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_vnode *dvnode = AFS_FS_I(dir);
struct afs_fid newfid; struct afs_fid newfid;
struct key *key; struct key *key;
u64 data_version = dvnode->status.data_version;
int ret; int ret;
_enter("{%x:%u},{%pd},%s", _enter("{%x:%u},{%pd},%s",
...@@ -1470,7 +1510,8 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1470,7 +1510,8 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
afs_fs_symlink(&fc, dentry->d_name.name, content, afs_fs_symlink(&fc, dentry->d_name.name,
content, data_version,
&newfid, &newstatus); &newfid, &newstatus);
} }
...@@ -1484,6 +1525,10 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1484,6 +1525,10 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
goto error_key; goto error_key;
} }
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
afs_edit_dir_add(dvnode, &dentry->d_name, &newfid,
afs_edit_dir_for_symlink);
key_put(key); key_put(key);
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
...@@ -1506,6 +1551,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1506,6 +1551,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
struct key *key; struct key *key;
u64 orig_data_version, new_data_version;
bool new_negative = d_is_negative(new_dentry);
int ret; int ret;
if (flags) if (flags)
...@@ -1514,6 +1561,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1514,6 +1561,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
vnode = AFS_FS_I(d_inode(old_dentry)); vnode = AFS_FS_I(d_inode(old_dentry));
orig_dvnode = AFS_FS_I(old_dir); orig_dvnode = AFS_FS_I(old_dir);
new_dvnode = AFS_FS_I(new_dir); new_dvnode = AFS_FS_I(new_dir);
orig_data_version = orig_dvnode->status.data_version;
new_data_version = new_dvnode->status.data_version;
_enter("{%x:%u},{%x:%u},{%x:%u},{%pd}", _enter("{%x:%u},{%x:%u},{%x:%u},{%pd}",
orig_dvnode->fid.vid, orig_dvnode->fid.vnode, 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,7 +1588,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break; 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_2 = new_dvnode->cb_break + new_dvnode->cb_s_break;
afs_fs_rename(&fc, old_dentry->d_name.name, afs_fs_rename(&fc, old_dentry->d_name.name,
new_dvnode, new_dentry->d_name.name); new_dvnode, new_dentry->d_name.name,
orig_data_version, new_data_version);
} }
afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break); 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,6 +1601,21 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto error_key; goto error_key;
} }
if (ret == 0) {
if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags))
afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name,
afs_edit_dir_for_rename);
if (!new_negative &&
test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
afs_edit_dir_remove(new_dvnode, &new_dentry->d_name,
afs_edit_dir_for_rename);
if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
afs_edit_dir_add(new_dvnode, &new_dentry->d_name,
&vnode->fid, afs_edit_dir_for_rename);
}
error_key: error_key:
key_put(key); key_put(key);
error: error:
......
This diff is collapsed.
...@@ -107,6 +107,13 @@ void afs_update_inode_from_status(struct afs_vnode *vnode, ...@@ -107,6 +107,13 @@ void afs_update_inode_from_status(struct afs_vnode *vnode,
} else { } else {
set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
} }
} else if (vnode->status.type == AFS_FTYPE_DIR) {
/* Expected directory change is handled elsewhere so
* that we can locally edit the directory and save on a
* download.
*/
if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
flags &= ~AFS_VNODE_DATA_CHANGED;
} }
} }
...@@ -190,10 +197,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp, ...@@ -190,10 +197,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
size = (u64)ntohl(xdr->size_lo); size = (u64)ntohl(xdr->size_lo);
size |= (u64)ntohl(xdr->size_hi) << 32; size |= (u64)ntohl(xdr->size_hi) << 32;
if (size != status->size) { status->size = size;
status->size = size;
flags |= AFS_VNODE_DATA_CHANGED;
}
data_version = (u64)ntohl(xdr->data_version_lo); data_version = (u64)ntohl(xdr->data_version_lo);
data_version |= (u64)ntohl(xdr->data_version_hi) << 32; data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
...@@ -736,6 +740,7 @@ static const struct afs_call_type afs_RXFSMakeDir = { ...@@ -736,6 +740,7 @@ static const struct afs_call_type afs_RXFSMakeDir = {
int afs_fs_create(struct afs_fs_cursor *fc, int afs_fs_create(struct afs_fs_cursor *fc,
const char *name, const char *name,
umode_t mode, umode_t mode,
u64 current_data_version,
struct afs_fid *newfid, struct afs_fid *newfid,
struct afs_file_status *newstatus, struct afs_file_status *newstatus,
struct afs_callback *newcb) struct afs_callback *newcb)
...@@ -763,7 +768,7 @@ int afs_fs_create(struct afs_fs_cursor *fc, ...@@ -763,7 +768,7 @@ int afs_fs_create(struct afs_fs_cursor *fc,
call->reply[1] = newfid; call->reply[1] = newfid;
call->reply[2] = newstatus; call->reply[2] = newstatus;
call->reply[3] = newcb; call->reply[3] = newcb;
call->expected_version = vnode->status.data_version; call->expected_version = current_data_version + 1;
/* marshall the parameters */ /* marshall the parameters */
bp = call->request; bp = call->request;
...@@ -836,7 +841,8 @@ static const struct afs_call_type afs_RXFSRemoveDir = { ...@@ -836,7 +841,8 @@ static const struct afs_call_type afs_RXFSRemoveDir = {
/* /*
* remove a file or directory * remove a file or directory
*/ */
int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir) int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir,
u64 current_data_version)
{ {
struct afs_vnode *vnode = fc->vnode; struct afs_vnode *vnode = fc->vnode;
struct afs_call *call; struct afs_call *call;
...@@ -858,7 +864,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir) ...@@ -858,7 +864,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir)
call->key = fc->key; call->key = fc->key;
call->reply[0] = vnode; call->reply[0] = vnode;
call->expected_version = vnode->status.data_version; call->expected_version = current_data_version + 1;
/* marshall the parameters */ /* marshall the parameters */
bp = call->request; bp = call->request;
...@@ -920,7 +926,7 @@ static const struct afs_call_type afs_RXFSLink = { ...@@ -920,7 +926,7 @@ static const struct afs_call_type afs_RXFSLink = {
* make a hard link * make a hard link
*/ */
int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
const char *name) const char *name, u64 current_data_version)
{ {
struct afs_vnode *dvnode = fc->vnode; struct afs_vnode *dvnode = fc->vnode;
struct afs_call *call; struct afs_call *call;
...@@ -941,7 +947,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, ...@@ -941,7 +947,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
call->key = fc->key; call->key = fc->key;
call->reply[0] = dvnode; call->reply[0] = dvnode;
call->reply[1] = vnode; call->reply[1] = vnode;
call->expected_version = vnode->status.data_version; call->expected_version = current_data_version + 1;
/* marshall the parameters */ /* marshall the parameters */
bp = call->request; bp = call->request;
...@@ -1009,6 +1015,7 @@ static const struct afs_call_type afs_RXFSSymlink = { ...@@ -1009,6 +1015,7 @@ static const struct afs_call_type afs_RXFSSymlink = {
int afs_fs_symlink(struct afs_fs_cursor *fc, int afs_fs_symlink(struct afs_fs_cursor *fc,
const char *name, const char *name,
const char *contents, const char *contents,
u64 current_data_version,
struct afs_fid *newfid, struct afs_fid *newfid,
struct afs_file_status *newstatus) struct afs_file_status *newstatus)
{ {
...@@ -1037,7 +1044,7 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, ...@@ -1037,7 +1044,7 @@ int afs_fs_symlink(struct afs_fs_cursor *fc,
call->reply[0] = vnode; call->reply[0] = vnode;
call->reply[1] = newfid; call->reply[1] = newfid;
call->reply[2] = newstatus; call->reply[2] = newstatus;
call->expected_version = vnode->status.data_version; call->expected_version = current_data_version + 1;
/* marshall the parameters */ /* marshall the parameters */
bp = call->request; bp = call->request;
...@@ -1117,7 +1124,9 @@ static const struct afs_call_type afs_RXFSRename = { ...@@ -1117,7 +1124,9 @@ static const struct afs_call_type afs_RXFSRename = {
int afs_fs_rename(struct afs_fs_cursor *fc, int afs_fs_rename(struct afs_fs_cursor *fc,
const char *orig_name, const char *orig_name,
struct afs_vnode *new_dvnode, struct afs_vnode *new_dvnode,
const char *new_name) const char *new_name,
u64 current_orig_data_version,
u64 current_new_data_version)
{ {
struct afs_vnode *orig_dvnode = fc->vnode; struct afs_vnode *orig_dvnode = fc->vnode;
struct afs_call *call; struct afs_call *call;
...@@ -1145,8 +1154,8 @@ int afs_fs_rename(struct afs_fs_cursor *fc, ...@@ -1145,8 +1154,8 @@ int afs_fs_rename(struct afs_fs_cursor *fc,
call->key = fc->key; call->key = fc->key;
call->reply[0] = orig_dvnode; call->reply[0] = orig_dvnode;
call->reply[1] = new_dvnode; call->reply[1] = new_dvnode;
call->expected_version = orig_dvnode->status.data_version; call->expected_version = current_orig_data_version + 1;
call->expected_version_2 = new_dvnode->status.data_version; call->expected_version_2 = current_new_data_version + 1;
/* marshall the parameters */ /* marshall the parameters */
bp = call->request; bp = call->request;
......
...@@ -395,8 +395,11 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) ...@@ -395,8 +395,11 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) { if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) {
vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
} else if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) && } else if (vnode->status.type == AFS_FTYPE_DIR &&
!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) &&
vnode->cb_expires_at - 10 > now) {
valid = true;
} else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
vnode->cb_expires_at - 10 > now) { vnode->cb_expires_at - 10 > now) {
valid = true; valid = true;
} }
......
...@@ -271,6 +271,8 @@ struct afs_net { ...@@ -271,6 +271,8 @@ struct afs_net {
atomic_t n_inval; /* Number of invalidations by the server */ atomic_t n_inval; /* Number of invalidations by the server */
atomic_t n_relpg; /* Number of invalidations by releasepage */ atomic_t n_relpg; /* Number of invalidations by releasepage */
atomic_t n_read_dir; /* Number of directory pages read */ atomic_t n_read_dir; /* Number of directory pages read */
atomic_t n_dir_cr; /* Number of directory entry creation edits */
atomic_t n_dir_rm; /* Number of directory entry removal edits */
}; };
extern const char afs_init_sysname[]; extern const char afs_init_sysname[];
...@@ -679,6 +681,13 @@ extern const struct dentry_operations afs_fs_dentry_operations; ...@@ -679,6 +681,13 @@ extern const struct dentry_operations afs_fs_dentry_operations;
extern void afs_d_release(struct dentry *); extern void afs_d_release(struct dentry *);
/*
* dir_edit.c
*/
extern void afs_edit_dir_add(struct afs_vnode *, struct qstr *, struct afs_fid *,
enum afs_edit_dir_reason);
extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, enum afs_edit_dir_reason);
/* /*
* dynroot.c * dynroot.c
*/ */
...@@ -725,14 +734,14 @@ extern void afs_update_inode_from_status(struct afs_vnode *, struct afs_file_sta ...@@ -725,14 +734,14 @@ extern void afs_update_inode_from_status(struct afs_vnode *, struct afs_file_sta
extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool); extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool);
extern int afs_fs_give_up_callbacks(struct afs_net *, struct afs_server *); extern int afs_fs_give_up_callbacks(struct afs_net *, struct afs_server *);
extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *); extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *);
extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, u64,
struct afs_fid *, struct afs_file_status *, struct afs_callback *); struct afs_fid *, struct afs_file_status *, struct afs_callback *);
extern int afs_fs_remove(struct afs_fs_cursor *, const char *, bool); extern int afs_fs_remove(struct afs_fs_cursor *, const char *, bool, u64);
extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *); extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64);
extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64,
struct afs_fid *, struct afs_file_status *); struct afs_fid *, struct afs_file_status *);
extern int afs_fs_rename(struct afs_fs_cursor *, const char *, extern int afs_fs_rename(struct afs_fs_cursor *, const char *,
struct afs_vnode *, const char *); struct afs_vnode *, const char *, u64, u64);
extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *, extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *,
pgoff_t, pgoff_t, unsigned, unsigned); pgoff_t, pgoff_t, unsigned, unsigned);
extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *); extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *);
......
...@@ -918,6 +918,10 @@ static int afs_proc_stats_show(struct seq_file *m, void *v) ...@@ -918,6 +918,10 @@ static int afs_proc_stats_show(struct seq_file *m, void *v)
seq_printf(m, "dir-data: rdpg=%u\n", seq_printf(m, "dir-data: rdpg=%u\n",
atomic_read(&net->n_read_dir)); atomic_read(&net->n_read_dir));
seq_printf(m, "dir-edit: cr=%u rm=%u\n",
atomic_read(&net->n_dir_cr),
atomic_read(&net->n_dir_rm));
return 0; return 0;
} }
......
...@@ -63,6 +63,27 @@ enum afs_vl_operation { ...@@ -63,6 +63,27 @@ enum afs_vl_operation {
afs_VL_GetCapabilities = 65537, /* AFS Get VL server capabilities */ afs_VL_GetCapabilities = 65537, /* AFS Get VL server capabilities */
}; };
enum afs_edit_dir_op {
afs_edit_dir_create,
afs_edit_dir_create_error,
afs_edit_dir_create_inval,
afs_edit_dir_create_nospc,
afs_edit_dir_delete,
afs_edit_dir_delete_error,
afs_edit_dir_delete_inval,
afs_edit_dir_delete_noent,
};
enum afs_edit_dir_reason {
afs_edit_dir_for_create,
afs_edit_dir_for_link,
afs_edit_dir_for_mkdir,
afs_edit_dir_for_rename,
afs_edit_dir_for_rmdir,
afs_edit_dir_for_symlink,
afs_edit_dir_for_unlink,
};
#endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */ #endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */
/* /*
...@@ -106,6 +127,25 @@ enum afs_vl_operation { ...@@ -106,6 +127,25 @@ enum afs_vl_operation {
EM(afs_YFSVL_GetEndpoints, "YFSVL.GetEndpoints") \ EM(afs_YFSVL_GetEndpoints, "YFSVL.GetEndpoints") \
E_(afs_VL_GetCapabilities, "VL.GetCapabilities") E_(afs_VL_GetCapabilities, "VL.GetCapabilities")
#define afs_edit_dir_ops \
EM(afs_edit_dir_create, "create") \
EM(afs_edit_dir_create_error, "c_fail") \
EM(afs_edit_dir_create_inval, "c_invl") \
EM(afs_edit_dir_create_nospc, "c_nspc") \
EM(afs_edit_dir_delete, "delete") \
EM(afs_edit_dir_delete_error, "d_err ") \
EM(afs_edit_dir_delete_inval, "d_invl") \
E_(afs_edit_dir_delete_noent, "d_nent")
#define afs_edit_dir_reasons \
EM(afs_edit_dir_for_create, "Create") \
EM(afs_edit_dir_for_link, "Link ") \
EM(afs_edit_dir_for_mkdir, "MkDir ") \
EM(afs_edit_dir_for_rename, "Rename") \
EM(afs_edit_dir_for_rmdir, "RmDir ") \
EM(afs_edit_dir_for_symlink, "Symlnk") \
E_(afs_edit_dir_for_unlink, "Unlink")
/* /*
* Export enum symbols via userspace. * Export enum symbols via userspace.
...@@ -118,6 +158,8 @@ enum afs_vl_operation { ...@@ -118,6 +158,8 @@ enum afs_vl_operation {
afs_call_traces; afs_call_traces;
afs_fs_operations; afs_fs_operations;
afs_vl_operations; afs_vl_operations;
afs_edit_dir_ops;
afs_edit_dir_reasons;
/* /*
* Now redefine the EM() and E_() macros to map the enums to the strings that * 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,6 +506,54 @@ TRACE_EVENT(afs_call_state,
__entry->ret, __entry->abort) __entry->ret, __entry->abort)
); );
TRACE_EVENT(afs_edit_dir,
TP_PROTO(struct afs_vnode *dvnode,
enum afs_edit_dir_reason why,
enum afs_edit_dir_op op,
unsigned int block,
unsigned int slot,
unsigned int f_vnode,
unsigned int f_unique,
const char *name),
TP_ARGS(dvnode, why, op, block, slot, f_vnode, f_unique, name),
TP_STRUCT__entry(
__field(unsigned int, vnode )
__field(unsigned int, unique )
__field(enum afs_edit_dir_reason, why )
__field(enum afs_edit_dir_op, op )
__field(unsigned int, block )
__field(unsigned short, slot )
__field(unsigned int, f_vnode )
__field(unsigned int, f_unique )
__array(char, name, 18 )
),
TP_fast_assign(
int __len = strlen(name);
__len = min(__len, 17);
__entry->vnode = dvnode->fid.vnode;
__entry->unique = dvnode->fid.unique;
__entry->why = why;
__entry->op = op;
__entry->block = block;
__entry->slot = slot;
__entry->f_vnode = f_vnode;
__entry->f_unique = f_unique;
memcpy(__entry->name, name, __len);
__entry->name[__len] = 0;
),
TP_printk("d=%x:%x %s %s %u[%u] f=%x:%x %s",
__entry->vnode, __entry->unique,
__print_symbolic(__entry->why, afs_edit_dir_reasons),
__print_symbolic(__entry->op, afs_edit_dir_ops),
__entry->block, __entry->slot,
__entry->f_vnode, __entry->f_unique,
__entry->name)
);
#endif /* _TRACE_AFS_H */ #endif /* _TRACE_AFS_H */
/* This part must be outside protection */ /* This part must be outside protection */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment