Commit 26c20ffc authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'afs-fixes-20200616' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull AFS fixes from David Howells:
 "I've managed to get xfstests kind of working with afs. Here are a set
  of patches that fix most of the bugs found.

  There are a number of primary issues:

   - Incorrect handling of mtime and non-handling of ctime. It might be
     argued, that the latter isn't a bug since the AFS protocol doesn't
     support ctime, but I should probably still update it locally.

   - Shared-write mmap, truncate and writeback bugs. This includes not
     changing i_size under the callback lock, overwriting local i_size
     with the reply from the server after a partial writeback, not
     limiting the writeback from an mmapped page to EOF.

   - Checks for an abort code indicating that the primary vnode in an
     operation was deleted by a third-party are done in the wrong place.

   - Silly rename bugs. This includes an incomplete conversion to the
     new operation handling, duplicate nlink handling, nlink changing
     not being done inside the callback lock and insufficient handling
     of third-party conflicting directory changes.

  And some secondary ones:

   - The UAEOVERFLOW abort code should map to EOVERFLOW not EREMOTEIO.

   - Remove a couple of unused or incompletely used bits.

   - Remove a couple of redundant success checks.

  These seem to fix all the data-corruption bugs found by

	./check -afs -g quick

  along with the obvious silly rename bugs and time bugs.

  There are still some test failures, but they seem to fall into two
  classes: firstly, the authentication/security model is different to
  the standard UNIX model and permission is arbitrated by the server and
  cached locally; and secondly, there are a number of features that AFS
  does not support (such as mknod). But in these cases, the tests
  themselves need to be adapted or skipped.

  Using the in-kernel afs client with xfstests also found a bug in the
  AuriStor AFS server that has been fixed for a future release"

* tag 'afs-fixes-20200616' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  afs: Fix silly rename
  afs: afs_vnode_commit_status() doesn't need to check the RPC error
  afs: Fix use of afs_check_for_remote_deletion()
  afs: Remove afs_operation::abort_code
  afs: Fix yfs_fs_fetch_status() to honour vnode selector
  afs: Remove yfs_fs_fetch_file_status() as it's not used
  afs: Fix the mapping of the UAEOVERFLOW abort code
  afs: Fix truncation issues and mmap writeback size
  afs: Concoct ctimes
  afs: Fix EOF corruption
  afs: afs_write_end() should change i_size under the right lock
  afs: Fix non-setting of mtime when writing into mmap
parents f17957f7 b6489a49
...@@ -648,7 +648,7 @@ static void afs_do_lookup_success(struct afs_operation *op) ...@@ -648,7 +648,7 @@ static void afs_do_lookup_success(struct afs_operation *op)
vp = &op->file[0]; vp = &op->file[0];
abort_code = vp->scb.status.abort_code; abort_code = vp->scb.status.abort_code;
if (abort_code != 0) { if (abort_code != 0) {
op->abort_code = abort_code; op->ac.abort_code = abort_code;
op->error = afs_abort_to_error(abort_code); op->error = afs_abort_to_error(abort_code);
} }
break; break;
...@@ -696,10 +696,11 @@ static const struct afs_operation_ops afs_inline_bulk_status_operation = { ...@@ -696,10 +696,11 @@ static const struct afs_operation_ops afs_inline_bulk_status_operation = {
.success = afs_do_lookup_success, .success = afs_do_lookup_success,
}; };
static const struct afs_operation_ops afs_fetch_status_operation = { static const struct afs_operation_ops afs_lookup_fetch_status_operation = {
.issue_afs_rpc = afs_fs_fetch_status, .issue_afs_rpc = afs_fs_fetch_status,
.issue_yfs_rpc = yfs_fs_fetch_status, .issue_yfs_rpc = yfs_fs_fetch_status,
.success = afs_do_lookup_success, .success = afs_do_lookup_success,
.aborted = afs_check_for_remote_deletion,
}; };
/* /*
...@@ -1236,6 +1237,17 @@ void afs_d_release(struct dentry *dentry) ...@@ -1236,6 +1237,17 @@ void afs_d_release(struct dentry *dentry)
_enter("%pd", dentry); _enter("%pd", dentry);
} }
void afs_check_for_remote_deletion(struct afs_operation *op)
{
struct afs_vnode *vnode = op->file[0].vnode;
switch (op->ac.abort_code) {
case VNOVNODE:
set_bit(AFS_VNODE_DELETED, &vnode->flags);
afs_break_callback(vnode, afs_cb_break_for_deleted);
}
}
/* /*
* Create a new inode for create/mkdir/symlink * Create a new inode for create/mkdir/symlink
*/ */
...@@ -1268,7 +1280,7 @@ static void afs_vnode_new_inode(struct afs_operation *op) ...@@ -1268,7 +1280,7 @@ static void afs_vnode_new_inode(struct afs_operation *op)
static void afs_create_success(struct afs_operation *op) static void afs_create_success(struct afs_operation *op)
{ {
_enter("op=%08x", op->debug_id); _enter("op=%08x", op->debug_id);
afs_check_for_remote_deletion(op, op->file[0].vnode); op->ctime = op->file[0].scb.status.mtime_client;
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
afs_update_dentry_version(op, &op->file[0], op->dentry); afs_update_dentry_version(op, &op->file[0], op->dentry);
afs_vnode_new_inode(op); afs_vnode_new_inode(op);
...@@ -1302,6 +1314,7 @@ static const struct afs_operation_ops afs_mkdir_operation = { ...@@ -1302,6 +1314,7 @@ static const struct afs_operation_ops afs_mkdir_operation = {
.issue_afs_rpc = afs_fs_make_dir, .issue_afs_rpc = afs_fs_make_dir,
.issue_yfs_rpc = yfs_fs_make_dir, .issue_yfs_rpc = yfs_fs_make_dir,
.success = afs_create_success, .success = afs_create_success,
.aborted = afs_check_for_remote_deletion,
.edit_dir = afs_create_edit_dir, .edit_dir = afs_create_edit_dir,
.put = afs_create_put, .put = afs_create_put,
}; };
...@@ -1325,6 +1338,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -1325,6 +1338,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
afs_op_set_vnode(op, 0, dvnode); afs_op_set_vnode(op, 0, dvnode);
op->file[0].dv_delta = 1; op->file[0].dv_delta = 1;
op->file[0].update_ctime = true;
op->dentry = dentry; op->dentry = dentry;
op->create.mode = S_IFDIR | mode; op->create.mode = S_IFDIR | mode;
op->create.reason = afs_edit_dir_for_mkdir; op->create.reason = afs_edit_dir_for_mkdir;
...@@ -1350,7 +1364,7 @@ static void afs_dir_remove_subdir(struct dentry *dentry) ...@@ -1350,7 +1364,7 @@ static void afs_dir_remove_subdir(struct dentry *dentry)
static void afs_rmdir_success(struct afs_operation *op) static void afs_rmdir_success(struct afs_operation *op)
{ {
_enter("op=%08x", op->debug_id); _enter("op=%08x", op->debug_id);
afs_check_for_remote_deletion(op, op->file[0].vnode); op->ctime = op->file[0].scb.status.mtime_client;
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
afs_update_dentry_version(op, &op->file[0], op->dentry); afs_update_dentry_version(op, &op->file[0], op->dentry);
} }
...@@ -1382,6 +1396,7 @@ static const struct afs_operation_ops afs_rmdir_operation = { ...@@ -1382,6 +1396,7 @@ static const struct afs_operation_ops afs_rmdir_operation = {
.issue_afs_rpc = afs_fs_remove_dir, .issue_afs_rpc = afs_fs_remove_dir,
.issue_yfs_rpc = yfs_fs_remove_dir, .issue_yfs_rpc = yfs_fs_remove_dir,
.success = afs_rmdir_success, .success = afs_rmdir_success,
.aborted = afs_check_for_remote_deletion,
.edit_dir = afs_rmdir_edit_dir, .edit_dir = afs_rmdir_edit_dir,
.put = afs_rmdir_put, .put = afs_rmdir_put,
}; };
...@@ -1404,6 +1419,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1404,6 +1419,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
afs_op_set_vnode(op, 0, dvnode); afs_op_set_vnode(op, 0, dvnode);
op->file[0].dv_delta = 1; op->file[0].dv_delta = 1;
op->file[0].update_ctime = true;
op->dentry = dentry; op->dentry = dentry;
op->ops = &afs_rmdir_operation; op->ops = &afs_rmdir_operation;
...@@ -1479,7 +1495,8 @@ static void afs_dir_remove_link(struct afs_operation *op) ...@@ -1479,7 +1495,8 @@ static void afs_dir_remove_link(struct afs_operation *op)
static void afs_unlink_success(struct afs_operation *op) static void afs_unlink_success(struct afs_operation *op)
{ {
_enter("op=%08x", op->debug_id); _enter("op=%08x", op->debug_id);
afs_check_for_remote_deletion(op, op->file[0].vnode); op->ctime = op->file[0].scb.status.mtime_client;
afs_check_dir_conflict(op, &op->file[0]);
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
afs_vnode_commit_status(op, &op->file[1]); afs_vnode_commit_status(op, &op->file[1]);
afs_update_dentry_version(op, &op->file[0], op->dentry); afs_update_dentry_version(op, &op->file[0], op->dentry);
...@@ -1511,6 +1528,7 @@ static const struct afs_operation_ops afs_unlink_operation = { ...@@ -1511,6 +1528,7 @@ static const struct afs_operation_ops afs_unlink_operation = {
.issue_afs_rpc = afs_fs_remove_file, .issue_afs_rpc = afs_fs_remove_file,
.issue_yfs_rpc = yfs_fs_remove_file, .issue_yfs_rpc = yfs_fs_remove_file,
.success = afs_unlink_success, .success = afs_unlink_success,
.aborted = afs_check_for_remote_deletion,
.edit_dir = afs_unlink_edit_dir, .edit_dir = afs_unlink_edit_dir,
.put = afs_unlink_put, .put = afs_unlink_put,
}; };
...@@ -1537,6 +1555,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1537,6 +1555,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
afs_op_set_vnode(op, 0, dvnode); afs_op_set_vnode(op, 0, dvnode);
op->file[0].dv_delta = 1; op->file[0].dv_delta = 1;
op->file[0].update_ctime = true;
/* Try to make sure we have a callback promise on the victim. */ /* Try to make sure we have a callback promise on the victim. */
ret = afs_validate(vnode, op->key); ret = afs_validate(vnode, op->key);
...@@ -1561,9 +1580,25 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1561,9 +1580,25 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
op->file[1].vnode = vnode; op->file[1].vnode = vnode;
op->file[1].update_ctime = true;
op->file[1].op_unlinked = true;
op->dentry = dentry; op->dentry = dentry;
op->ops = &afs_unlink_operation; op->ops = &afs_unlink_operation;
return afs_do_sync_operation(op); afs_begin_vnode_operation(op);
afs_wait_for_operation(op);
/* If there was a conflict with a third party, check the status of the
* unlinked vnode.
*/
if (op->error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) {
op->file[1].update_ctime = false;
op->fetch_status.which = 1;
op->ops = &afs_fetch_status_operation;
afs_begin_vnode_operation(op);
afs_wait_for_operation(op);
}
return afs_put_operation(op);
error: error:
return afs_put_operation(op); return afs_put_operation(op);
...@@ -1573,6 +1608,7 @@ static const struct afs_operation_ops afs_create_operation = { ...@@ -1573,6 +1608,7 @@ static const struct afs_operation_ops afs_create_operation = {
.issue_afs_rpc = afs_fs_create_file, .issue_afs_rpc = afs_fs_create_file,
.issue_yfs_rpc = yfs_fs_create_file, .issue_yfs_rpc = yfs_fs_create_file,
.success = afs_create_success, .success = afs_create_success,
.aborted = afs_check_for_remote_deletion,
.edit_dir = afs_create_edit_dir, .edit_dir = afs_create_edit_dir,
.put = afs_create_put, .put = afs_create_put,
}; };
...@@ -1601,6 +1637,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -1601,6 +1637,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
afs_op_set_vnode(op, 0, dvnode); afs_op_set_vnode(op, 0, dvnode);
op->file[0].dv_delta = 1; op->file[0].dv_delta = 1;
op->file[0].update_ctime = true;
op->dentry = dentry; op->dentry = dentry;
op->create.mode = S_IFREG | mode; op->create.mode = S_IFREG | mode;
...@@ -1620,6 +1657,7 @@ static void afs_link_success(struct afs_operation *op) ...@@ -1620,6 +1657,7 @@ static void afs_link_success(struct afs_operation *op)
struct afs_vnode_param *vp = &op->file[1]; struct afs_vnode_param *vp = &op->file[1];
_enter("op=%08x", op->debug_id); _enter("op=%08x", op->debug_id);
op->ctime = dvp->scb.status.mtime_client;
afs_vnode_commit_status(op, dvp); afs_vnode_commit_status(op, dvp);
afs_vnode_commit_status(op, vp); afs_vnode_commit_status(op, vp);
afs_update_dentry_version(op, dvp, op->dentry); afs_update_dentry_version(op, dvp, op->dentry);
...@@ -1640,6 +1678,7 @@ static const struct afs_operation_ops afs_link_operation = { ...@@ -1640,6 +1678,7 @@ static const struct afs_operation_ops afs_link_operation = {
.issue_afs_rpc = afs_fs_link, .issue_afs_rpc = afs_fs_link,
.issue_yfs_rpc = yfs_fs_link, .issue_yfs_rpc = yfs_fs_link,
.success = afs_link_success, .success = afs_link_success,
.aborted = afs_check_for_remote_deletion,
.edit_dir = afs_create_edit_dir, .edit_dir = afs_create_edit_dir,
.put = afs_link_put, .put = afs_link_put,
}; };
...@@ -1672,6 +1711,8 @@ static int afs_link(struct dentry *from, struct inode *dir, ...@@ -1672,6 +1711,8 @@ static int afs_link(struct dentry *from, struct inode *dir,
afs_op_set_vnode(op, 0, dvnode); afs_op_set_vnode(op, 0, dvnode);
afs_op_set_vnode(op, 1, vnode); afs_op_set_vnode(op, 1, vnode);
op->file[0].dv_delta = 1; op->file[0].dv_delta = 1;
op->file[0].update_ctime = true;
op->file[1].update_ctime = true;
op->dentry = dentry; op->dentry = dentry;
op->dentry_2 = from; op->dentry_2 = from;
...@@ -1689,6 +1730,7 @@ static const struct afs_operation_ops afs_symlink_operation = { ...@@ -1689,6 +1730,7 @@ static const struct afs_operation_ops afs_symlink_operation = {
.issue_afs_rpc = afs_fs_symlink, .issue_afs_rpc = afs_fs_symlink,
.issue_yfs_rpc = yfs_fs_symlink, .issue_yfs_rpc = yfs_fs_symlink,
.success = afs_create_success, .success = afs_create_success,
.aborted = afs_check_for_remote_deletion,
.edit_dir = afs_create_edit_dir, .edit_dir = afs_create_edit_dir,
.put = afs_create_put, .put = afs_create_put,
}; };
...@@ -1740,9 +1782,13 @@ static void afs_rename_success(struct afs_operation *op) ...@@ -1740,9 +1782,13 @@ static void afs_rename_success(struct afs_operation *op)
{ {
_enter("op=%08x", op->debug_id); _enter("op=%08x", op->debug_id);
op->ctime = op->file[0].scb.status.mtime_client;
afs_check_dir_conflict(op, &op->file[1]);
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
if (op->file[1].vnode != op->file[0].vnode) if (op->file[1].vnode != op->file[0].vnode) {
op->ctime = op->file[1].scb.status.mtime_client;
afs_vnode_commit_status(op, &op->file[1]); afs_vnode_commit_status(op, &op->file[1]);
}
} }
static void afs_rename_edit_dir(struct afs_operation *op) static void afs_rename_edit_dir(struct afs_operation *op)
...@@ -1860,6 +1906,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1860,6 +1906,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
afs_op_set_vnode(op, 1, new_dvnode); /* May be same as orig_dvnode */ afs_op_set_vnode(op, 1, new_dvnode); /* May be same as orig_dvnode */
op->file[0].dv_delta = 1; op->file[0].dv_delta = 1;
op->file[1].dv_delta = 1; op->file[1].dv_delta = 1;
op->file[0].update_ctime = true;
op->file[1].update_ctime = true;
op->dentry = old_dentry; op->dentry = old_dentry;
op->dentry_2 = new_dentry; op->dentry_2 = new_dentry;
......
...@@ -16,6 +16,7 @@ static void afs_silly_rename_success(struct afs_operation *op) ...@@ -16,6 +16,7 @@ static void afs_silly_rename_success(struct afs_operation *op)
{ {
_enter("op=%08x", op->debug_id); _enter("op=%08x", op->debug_id);
afs_check_dir_conflict(op, &op->file[0]);
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
} }
...@@ -69,6 +70,11 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode ...@@ -69,6 +70,11 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
return PTR_ERR(op); return PTR_ERR(op);
afs_op_set_vnode(op, 0, dvnode); afs_op_set_vnode(op, 0, dvnode);
afs_op_set_vnode(op, 1, dvnode);
op->file[0].dv_delta = 1;
op->file[1].dv_delta = 1;
op->file[0].update_ctime = true;
op->file[1].update_ctime = true;
op->dentry = old; op->dentry = old;
op->dentry_2 = new; op->dentry_2 = new;
...@@ -129,6 +135,7 @@ int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode, ...@@ -129,6 +135,7 @@ int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
switch (ret) { switch (ret) {
case 0: case 0:
/* The rename succeeded. */ /* The rename succeeded. */
set_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags);
d_move(dentry, sdentry); d_move(dentry, sdentry);
break; break;
case -ERESTARTSYS: case -ERESTARTSYS:
...@@ -148,19 +155,11 @@ int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode, ...@@ -148,19 +155,11 @@ int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
static void afs_silly_unlink_success(struct afs_operation *op) static void afs_silly_unlink_success(struct afs_operation *op)
{ {
struct afs_vnode *vnode = op->file[1].vnode;
_enter("op=%08x", op->debug_id); _enter("op=%08x", op->debug_id);
afs_check_for_remote_deletion(op, op->file[0].vnode); afs_check_dir_conflict(op, &op->file[0]);
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
afs_vnode_commit_status(op, &op->file[1]); afs_vnode_commit_status(op, &op->file[1]);
afs_update_dentry_version(op, &op->file[0], op->dentry); afs_update_dentry_version(op, &op->file[0], op->dentry);
drop_nlink(&vnode->vfs_inode);
if (vnode->vfs_inode.i_nlink == 0) {
set_bit(AFS_VNODE_DELETED, &vnode->flags);
clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
}
} }
static void afs_silly_unlink_edit_dir(struct afs_operation *op) static void afs_silly_unlink_edit_dir(struct afs_operation *op)
...@@ -181,6 +180,7 @@ static const struct afs_operation_ops afs_silly_unlink_operation = { ...@@ -181,6 +180,7 @@ static const struct afs_operation_ops afs_silly_unlink_operation = {
.issue_afs_rpc = afs_fs_remove_file, .issue_afs_rpc = afs_fs_remove_file,
.issue_yfs_rpc = yfs_fs_remove_file, .issue_yfs_rpc = yfs_fs_remove_file,
.success = afs_silly_unlink_success, .success = afs_silly_unlink_success,
.aborted = afs_check_for_remote_deletion,
.edit_dir = afs_silly_unlink_edit_dir, .edit_dir = afs_silly_unlink_edit_dir,
}; };
...@@ -200,12 +200,30 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode ...@@ -200,12 +200,30 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode
afs_op_set_vnode(op, 0, dvnode); afs_op_set_vnode(op, 0, dvnode);
afs_op_set_vnode(op, 1, vnode); afs_op_set_vnode(op, 1, vnode);
op->file[0].dv_delta = 1;
op->file[0].update_ctime = true;
op->file[1].op_unlinked = true;
op->file[1].update_ctime = true;
op->dentry = dentry; op->dentry = dentry;
op->ops = &afs_silly_unlink_operation; op->ops = &afs_silly_unlink_operation;
trace_afs_silly_rename(vnode, true); trace_afs_silly_rename(vnode, true);
return afs_do_sync_operation(op); afs_begin_vnode_operation(op);
afs_wait_for_operation(op);
/* If there was a conflict with a third party, check the status of the
* unlinked vnode.
*/
if (op->error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) {
op->file[1].update_ctime = false;
op->fetch_status.which = 1;
op->ops = &afs_fetch_status_operation;
afs_begin_vnode_operation(op);
afs_wait_for_operation(op);
}
return afs_put_operation(op);
} }
/* /*
......
...@@ -225,7 +225,6 @@ static void afs_fetch_data_success(struct afs_operation *op) ...@@ -225,7 +225,6 @@ static void afs_fetch_data_success(struct afs_operation *op)
struct afs_vnode *vnode = op->file[0].vnode; struct afs_vnode *vnode = op->file[0].vnode;
_enter("op=%08x", op->debug_id); _enter("op=%08x", op->debug_id);
afs_check_for_remote_deletion(op, vnode);
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
afs_stat_v(vnode, n_fetches); afs_stat_v(vnode, n_fetches);
atomic_long_add(op->fetch.req->actual_len, &op->net->n_fetch_bytes); atomic_long_add(op->fetch.req->actual_len, &op->net->n_fetch_bytes);
...@@ -240,6 +239,7 @@ static const struct afs_operation_ops afs_fetch_data_operation = { ...@@ -240,6 +239,7 @@ static const struct afs_operation_ops afs_fetch_data_operation = {
.issue_afs_rpc = afs_fs_fetch_data, .issue_afs_rpc = afs_fs_fetch_data,
.issue_yfs_rpc = yfs_fs_fetch_data, .issue_yfs_rpc = yfs_fs_fetch_data,
.success = afs_fetch_data_success, .success = afs_fetch_data_success,
.aborted = afs_check_for_remote_deletion,
.put = afs_fetch_data_put, .put = afs_fetch_data_put,
}; };
......
...@@ -175,10 +175,7 @@ static void afs_kill_lockers_enoent(struct afs_vnode *vnode) ...@@ -175,10 +175,7 @@ static void afs_kill_lockers_enoent(struct afs_vnode *vnode)
static void afs_lock_success(struct afs_operation *op) static void afs_lock_success(struct afs_operation *op)
{ {
struct afs_vnode *vnode = op->file[0].vnode;
_enter("op=%08x", op->debug_id); _enter("op=%08x", op->debug_id);
afs_check_for_remote_deletion(op, vnode);
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
} }
...@@ -186,6 +183,7 @@ static const struct afs_operation_ops afs_set_lock_operation = { ...@@ -186,6 +183,7 @@ static const struct afs_operation_ops afs_set_lock_operation = {
.issue_afs_rpc = afs_fs_set_lock, .issue_afs_rpc = afs_fs_set_lock,
.issue_yfs_rpc = yfs_fs_set_lock, .issue_yfs_rpc = yfs_fs_set_lock,
.success = afs_lock_success, .success = afs_lock_success,
.aborted = afs_check_for_remote_deletion,
}; };
/* /*
......
...@@ -187,9 +187,17 @@ void afs_wait_for_operation(struct afs_operation *op) ...@@ -187,9 +187,17 @@ void afs_wait_for_operation(struct afs_operation *op)
op->error = afs_wait_for_call_to_complete(op->call, &op->ac); op->error = afs_wait_for_call_to_complete(op->call, &op->ac);
} }
if (op->error == 0) { switch (op->error) {
case 0:
_debug("success"); _debug("success");
op->ops->success(op); op->ops->success(op);
break;
case -ECONNABORTED:
if (op->ops->aborted)
op->ops->aborted(op);
break;
default:
break;
} }
afs_end_vnode_operation(op); afs_end_vnode_operation(op);
......
...@@ -165,9 +165,11 @@ static void afs_apply_status(struct afs_operation *op, ...@@ -165,9 +165,11 @@ static void afs_apply_status(struct afs_operation *op,
{ {
struct afs_file_status *status = &vp->scb.status; struct afs_file_status *status = &vp->scb.status;
struct afs_vnode *vnode = vp->vnode; struct afs_vnode *vnode = vp->vnode;
struct inode *inode = &vnode->vfs_inode;
struct timespec64 t; struct timespec64 t;
umode_t mode; umode_t mode;
bool data_changed = false; bool data_changed = false;
bool change_size = vp->set_size;
_enter("{%llx:%llu.%u} %s", _enter("{%llx:%llu.%u} %s",
vp->fid.vid, vp->fid.vnode, vp->fid.unique, vp->fid.vid, vp->fid.vnode, vp->fid.unique,
...@@ -186,25 +188,25 @@ static void afs_apply_status(struct afs_operation *op, ...@@ -186,25 +188,25 @@ static void afs_apply_status(struct afs_operation *op,
} }
if (status->nlink != vnode->status.nlink) if (status->nlink != vnode->status.nlink)
set_nlink(&vnode->vfs_inode, status->nlink); set_nlink(inode, status->nlink);
if (status->owner != vnode->status.owner) if (status->owner != vnode->status.owner)
vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner); inode->i_uid = make_kuid(&init_user_ns, status->owner);
if (status->group != vnode->status.group) if (status->group != vnode->status.group)
vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group); inode->i_gid = make_kgid(&init_user_ns, status->group);
if (status->mode != vnode->status.mode) { if (status->mode != vnode->status.mode) {
mode = vnode->vfs_inode.i_mode; mode = inode->i_mode;
mode &= ~S_IALLUGO; mode &= ~S_IALLUGO;
mode |= status->mode; mode |= status->mode;
WRITE_ONCE(vnode->vfs_inode.i_mode, mode); WRITE_ONCE(inode->i_mode, mode);
} }
t = status->mtime_client; t = status->mtime_client;
vnode->vfs_inode.i_ctime = t; inode->i_mtime = t;
vnode->vfs_inode.i_mtime = t; if (vp->update_ctime)
vnode->vfs_inode.i_atime = t; inode->i_ctime = op->ctime;
if (vnode->status.data_version != status->data_version) if (vnode->status.data_version != status->data_version)
data_changed = true; data_changed = true;
...@@ -226,6 +228,7 @@ static void afs_apply_status(struct afs_operation *op, ...@@ -226,6 +228,7 @@ static void afs_apply_status(struct afs_operation *op,
} else { } else {
set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
} }
change_size = true;
} else if (vnode->status.type == AFS_FTYPE_DIR) { } else if (vnode->status.type == AFS_FTYPE_DIR) {
/* Expected directory change is handled elsewhere so /* Expected directory change is handled elsewhere so
* that we can locally edit the directory and save on a * that we can locally edit the directory and save on a
...@@ -233,11 +236,22 @@ static void afs_apply_status(struct afs_operation *op, ...@@ -233,11 +236,22 @@ static void afs_apply_status(struct afs_operation *op,
*/ */
if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
data_changed = false; data_changed = false;
change_size = true;
} }
if (data_changed) { if (data_changed) {
inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); inode_set_iversion_raw(inode, status->data_version);
afs_set_i_size(vnode, status->size);
/* Only update the size if the data version jumped. If the
* file is being modified locally, then we might have our own
* idea of what the size should be that's not the same as
* what's on the server.
*/
if (change_size) {
afs_set_i_size(vnode, status->size);
inode->i_ctime = t;
inode->i_atime = t;
}
} }
} }
...@@ -267,32 +281,39 @@ void afs_vnode_commit_status(struct afs_operation *op, struct afs_vnode_param *v ...@@ -267,32 +281,39 @@ void afs_vnode_commit_status(struct afs_operation *op, struct afs_vnode_param *v
_enter(""); _enter("");
ASSERTCMP(op->error, ==, 0);
write_seqlock(&vnode->cb_lock); write_seqlock(&vnode->cb_lock);
if (vp->scb.have_error) { if (vp->scb.have_error) {
/* A YFS server will return this from RemoveFile2 and AFS and
* YFS will return this from InlineBulkStatus.
*/
if (vp->scb.status.abort_code == VNOVNODE) { if (vp->scb.status.abort_code == VNOVNODE) {
set_bit(AFS_VNODE_DELETED, &vnode->flags); set_bit(AFS_VNODE_DELETED, &vnode->flags);
clear_nlink(&vnode->vfs_inode); clear_nlink(&vnode->vfs_inode);
__afs_break_callback(vnode, afs_cb_break_for_deleted); __afs_break_callback(vnode, afs_cb_break_for_deleted);
op->flags &= ~AFS_OPERATION_DIR_CONFLICT;
} }
} else { } else if (vp->scb.have_status) {
if (vp->scb.have_status) afs_apply_status(op, vp);
afs_apply_status(op, vp);
if (vp->scb.have_cb) if (vp->scb.have_cb)
afs_apply_callback(op, vp); afs_apply_callback(op, vp);
} else if (vp->op_unlinked && !(op->flags & AFS_OPERATION_DIR_CONFLICT)) {
drop_nlink(&vnode->vfs_inode);
if (vnode->vfs_inode.i_nlink == 0) {
set_bit(AFS_VNODE_DELETED, &vnode->flags);
__afs_break_callback(vnode, afs_cb_break_for_deleted);
}
} }
write_sequnlock(&vnode->cb_lock); write_sequnlock(&vnode->cb_lock);
if (op->error == 0 && vp->scb.have_status) if (vp->scb.have_status)
afs_cache_permit(vnode, op->key, vp->cb_break_before, &vp->scb); afs_cache_permit(vnode, op->key, vp->cb_break_before, &vp->scb);
} }
static void afs_fetch_status_success(struct afs_operation *op) static void afs_fetch_status_success(struct afs_operation *op)
{ {
struct afs_vnode_param *vp = &op->file[0]; struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
struct afs_vnode *vnode = vp->vnode; struct afs_vnode *vnode = vp->vnode;
int ret; int ret;
...@@ -306,10 +327,11 @@ static void afs_fetch_status_success(struct afs_operation *op) ...@@ -306,10 +327,11 @@ static void afs_fetch_status_success(struct afs_operation *op)
} }
} }
static const struct afs_operation_ops afs_fetch_status_operation = { const struct afs_operation_ops afs_fetch_status_operation = {
.issue_afs_rpc = afs_fs_fetch_status, .issue_afs_rpc = afs_fs_fetch_status,
.issue_yfs_rpc = yfs_fs_fetch_status, .issue_yfs_rpc = yfs_fs_fetch_status,
.success = afs_fetch_status_success, .success = afs_fetch_status_success,
.aborted = afs_check_for_remote_deletion,
}; };
/* /*
...@@ -716,6 +738,9 @@ int afs_getattr(const struct path *path, struct kstat *stat, ...@@ -716,6 +738,9 @@ int afs_getattr(const struct path *path, struct kstat *stat,
do { do {
read_seqbegin_or_lock(&vnode->cb_lock, &seq); read_seqbegin_or_lock(&vnode->cb_lock, &seq);
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
if (test_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags) &&
stat->nlink > 0)
stat->nlink -= 1;
} while (need_seqretry(&vnode->cb_lock, seq)); } while (need_seqretry(&vnode->cb_lock, seq));
done_seqretry(&vnode->cb_lock, seq); done_seqretry(&vnode->cb_lock, seq);
...@@ -785,7 +810,15 @@ void afs_evict_inode(struct inode *inode) ...@@ -785,7 +810,15 @@ void afs_evict_inode(struct inode *inode)
static void afs_setattr_success(struct afs_operation *op) static void afs_setattr_success(struct afs_operation *op)
{ {
struct inode *inode = &op->file[0].vnode->vfs_inode;
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
if (op->setattr.attr->ia_valid & ATTR_SIZE) {
loff_t i_size = inode->i_size, size = op->setattr.attr->ia_size;
if (size > i_size)
pagecache_isize_extended(inode, i_size, size);
truncate_pagecache(inode, size);
}
} }
static const struct afs_operation_ops afs_setattr_operation = { static const struct afs_operation_ops afs_setattr_operation = {
...@@ -801,17 +834,31 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -801,17 +834,31 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
{ {
struct afs_operation *op; struct afs_operation *op;
struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
int ret;
_enter("{%llx:%llu},{n=%pd},%x", _enter("{%llx:%llu},{n=%pd},%x",
vnode->fid.vid, vnode->fid.vnode, dentry, vnode->fid.vid, vnode->fid.vnode, dentry,
attr->ia_valid); attr->ia_valid);
if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID | if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
ATTR_MTIME))) { ATTR_MTIME | ATTR_MTIME_SET | ATTR_TIMES_SET |
ATTR_TOUCH))) {
_leave(" = 0 [unsupported]"); _leave(" = 0 [unsupported]");
return 0; return 0;
} }
if (attr->ia_valid & ATTR_SIZE) {
if (!S_ISREG(vnode->vfs_inode.i_mode))
return -EISDIR;
ret = inode_newsize_ok(&vnode->vfs_inode, attr->ia_size);
if (ret)
return ret;
if (attr->ia_size == i_size_read(&vnode->vfs_inode))
attr->ia_valid &= ~ATTR_SIZE;
}
/* flush any dirty data outstanding on a regular file */ /* flush any dirty data outstanding on a regular file */
if (S_ISREG(vnode->vfs_inode.i_mode)) if (S_ISREG(vnode->vfs_inode.i_mode))
filemap_write_and_wait(vnode->vfs_inode.i_mapping); filemap_write_and_wait(vnode->vfs_inode.i_mapping);
...@@ -825,8 +872,12 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -825,8 +872,12 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
afs_op_set_vnode(op, 0, vnode); afs_op_set_vnode(op, 0, vnode);
op->setattr.attr = attr; op->setattr.attr = attr;
if (attr->ia_valid & ATTR_SIZE) if (attr->ia_valid & ATTR_SIZE) {
op->file[0].dv_delta = 1; op->file[0].dv_delta = 1;
op->file[0].set_size = true;
}
op->ctime = attr->ia_ctime;
op->file[0].update_ctime = 1;
op->ops = &afs_setattr_operation; op->ops = &afs_setattr_operation;
return afs_do_sync_operation(op); return afs_do_sync_operation(op);
......
...@@ -634,6 +634,7 @@ struct afs_vnode { ...@@ -634,6 +634,7 @@ struct afs_vnode {
#define AFS_VNODE_AUTOCELL 6 /* set if Vnode is an auto mount point */ #define AFS_VNODE_AUTOCELL 6 /* set if Vnode is an auto mount point */
#define AFS_VNODE_PSEUDODIR 7 /* set if Vnode is a pseudo directory */ #define AFS_VNODE_PSEUDODIR 7 /* set if Vnode is a pseudo directory */
#define AFS_VNODE_NEW_CONTENT 8 /* Set if file has new content (create/trunc-0) */ #define AFS_VNODE_NEW_CONTENT 8 /* Set if file has new content (create/trunc-0) */
#define AFS_VNODE_SILLY_DELETED 9 /* Set if file has been silly-deleted */
struct list_head wb_keys; /* List of keys available for writeback */ struct list_head wb_keys; /* List of keys available for writeback */
struct list_head pending_locks; /* locks waiting to be granted */ struct list_head pending_locks; /* locks waiting to be granted */
...@@ -744,8 +745,11 @@ struct afs_vnode_param { ...@@ -744,8 +745,11 @@ struct afs_vnode_param {
afs_dataversion_t dv_before; /* Data version before the call */ afs_dataversion_t dv_before; /* Data version before the call */
unsigned int cb_break_before; /* cb_break + cb_s_break before the call */ unsigned int cb_break_before; /* cb_break + cb_s_break before the call */
u8 dv_delta; /* Expected change in data version */ u8 dv_delta; /* Expected change in data version */
bool put_vnode; /* T if we have a ref on the vnode */ bool put_vnode:1; /* T if we have a ref on the vnode */
bool need_io_lock; /* T if we need the I/O lock on this */ bool need_io_lock:1; /* T if we need the I/O lock on this */
bool update_ctime:1; /* Need to update the ctime */
bool set_size:1; /* Must update i_size */
bool op_unlinked:1; /* True if file was unlinked by op */
}; };
/* /*
...@@ -766,9 +770,9 @@ struct afs_operation { ...@@ -766,9 +770,9 @@ struct afs_operation {
struct dentry *dentry; /* Dentry to be altered */ struct dentry *dentry; /* Dentry to be altered */
struct dentry *dentry_2; /* Second dentry to be altered */ struct dentry *dentry_2; /* Second dentry to be altered */
struct timespec64 mtime; /* Modification time to record */ struct timespec64 mtime; /* Modification time to record */
struct timespec64 ctime; /* Change time to set */
short nr_files; /* Number of entries in file[], more_files */ short nr_files; /* Number of entries in file[], more_files */
short error; short error;
unsigned int abort_code;
unsigned int debug_id; unsigned int debug_id;
unsigned int cb_v_break; /* Volume break counter before op */ unsigned int cb_v_break; /* Volume break counter before op */
...@@ -837,6 +841,7 @@ struct afs_operation { ...@@ -837,6 +841,7 @@ struct afs_operation {
#define AFS_OPERATION_LOCK_1 0x0200 /* Set if have io_lock on file[1] */ #define AFS_OPERATION_LOCK_1 0x0200 /* Set if have io_lock on file[1] */
#define AFS_OPERATION_TRIED_ALL 0x0400 /* Set if we've tried all the fileservers */ #define AFS_OPERATION_TRIED_ALL 0x0400 /* Set if we've tried all the fileservers */
#define AFS_OPERATION_RETRY_SERVER 0x0800 /* Set if we should retry the current server */ #define AFS_OPERATION_RETRY_SERVER 0x0800 /* Set if we should retry the current server */
#define AFS_OPERATION_DIR_CONFLICT 0x1000 /* Set if we detected a 3rd-party dir change */
}; };
/* /*
...@@ -932,6 +937,7 @@ extern const struct address_space_operations afs_dir_aops; ...@@ -932,6 +937,7 @@ extern const struct address_space_operations afs_dir_aops;
extern const struct dentry_operations afs_fs_dentry_operations; extern const struct dentry_operations afs_fs_dentry_operations;
extern void afs_d_release(struct dentry *); extern void afs_d_release(struct dentry *);
extern void afs_check_for_remote_deletion(struct afs_operation *);
/* /*
* dir_edit.c * dir_edit.c
...@@ -1063,6 +1069,8 @@ extern int afs_wait_for_one_fs_probe(struct afs_server *, bool); ...@@ -1063,6 +1069,8 @@ extern int afs_wait_for_one_fs_probe(struct afs_server *, bool);
/* /*
* inode.c * inode.c
*/ */
extern const struct afs_operation_ops afs_fetch_status_operation;
extern void afs_vnode_commit_status(struct afs_operation *, struct afs_vnode_param *); extern void afs_vnode_commit_status(struct afs_operation *, struct afs_vnode_param *);
extern int afs_fetch_status(struct afs_vnode *, struct key *, bool, afs_access_t *); extern int afs_fetch_status(struct afs_vnode *, struct key *, bool, afs_access_t *);
extern int afs_ilookup5_test_by_fid(struct inode *, void *); extern int afs_ilookup5_test_by_fid(struct inode *, void *);
...@@ -1435,7 +1443,6 @@ extern ssize_t afs_listxattr(struct dentry *, char *, size_t); ...@@ -1435,7 +1443,6 @@ extern ssize_t afs_listxattr(struct dentry *, char *, size_t);
/* /*
* yfsclient.c * yfsclient.c
*/ */
extern void yfs_fs_fetch_file_status(struct afs_operation *);
extern void yfs_fs_fetch_data(struct afs_operation *); extern void yfs_fs_fetch_data(struct afs_operation *);
extern void yfs_fs_create_file(struct afs_operation *); extern void yfs_fs_create_file(struct afs_operation *);
extern void yfs_fs_make_dir(struct afs_operation *); extern void yfs_fs_make_dir(struct afs_operation *);
...@@ -1481,15 +1488,6 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode) ...@@ -1481,15 +1488,6 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
return &vnode->vfs_inode; return &vnode->vfs_inode;
} }
static inline void afs_check_for_remote_deletion(struct afs_operation *op,
struct afs_vnode *vnode)
{
if (op->error == -ENOENT) {
set_bit(AFS_VNODE_DELETED, &vnode->flags);
afs_break_callback(vnode, afs_cb_break_for_deleted);
}
}
/* /*
* Note that a dentry got changed. We need to set d_fsdata to the data version * Note that a dentry got changed. We need to set d_fsdata to the data version
* number derived from the result of the operation. It doesn't matter if * number derived from the result of the operation. It doesn't matter if
...@@ -1504,6 +1502,18 @@ static inline void afs_update_dentry_version(struct afs_operation *op, ...@@ -1504,6 +1502,18 @@ static inline void afs_update_dentry_version(struct afs_operation *op,
(void *)(unsigned long)dir_vp->scb.status.data_version; (void *)(unsigned long)dir_vp->scb.status.data_version;
} }
/*
* Check for a conflicting operation on a directory that we just unlinked from.
* If someone managed to sneak a link or an unlink in on the file we just
* unlinked, we won't be able to trust nlink on an AFS file (but not YFS).
*/
static inline void afs_check_dir_conflict(struct afs_operation *op,
struct afs_vnode_param *dvp)
{
if (dvp->dv_before + dvp->dv_delta != dvp->scb.status.data_version)
op->flags |= AFS_OPERATION_DIR_CONFLICT;
}
static inline int afs_io_error(struct afs_call *call, enum afs_io_error where) static inline int afs_io_error(struct afs_call *call, enum afs_io_error where)
{ {
trace_afs_io_error(call->debug_id, -EIO, where); trace_afs_io_error(call->debug_id, -EIO, where);
......
...@@ -83,6 +83,7 @@ int afs_abort_to_error(u32 abort_code) ...@@ -83,6 +83,7 @@ int afs_abort_to_error(u32 abort_code)
case UAENOLCK: return -ENOLCK; case UAENOLCK: return -ENOLCK;
case UAENOTEMPTY: return -ENOTEMPTY; case UAENOTEMPTY: return -ENOTEMPTY;
case UAELOOP: return -ELOOP; case UAELOOP: return -ELOOP;
case UAEOVERFLOW: return -EOVERFLOW;
case UAENOMEDIUM: return -ENOMEDIUM; case UAENOMEDIUM: return -ENOMEDIUM;
case UAEDQUOT: return -EDQUOT; case UAEDQUOT: return -EDQUOT;
......
...@@ -194,11 +194,11 @@ int afs_write_end(struct file *file, struct address_space *mapping, ...@@ -194,11 +194,11 @@ int afs_write_end(struct file *file, struct address_space *mapping,
i_size = i_size_read(&vnode->vfs_inode); i_size = i_size_read(&vnode->vfs_inode);
if (maybe_i_size > i_size) { if (maybe_i_size > i_size) {
spin_lock(&vnode->wb_lock); write_seqlock(&vnode->cb_lock);
i_size = i_size_read(&vnode->vfs_inode); i_size = i_size_read(&vnode->vfs_inode);
if (maybe_i_size > i_size) if (maybe_i_size > i_size)
i_size_write(&vnode->vfs_inode, maybe_i_size); i_size_write(&vnode->vfs_inode, maybe_i_size);
spin_unlock(&vnode->wb_lock); write_sequnlock(&vnode->cb_lock);
} }
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
...@@ -393,6 +393,7 @@ static void afs_store_data_success(struct afs_operation *op) ...@@ -393,6 +393,7 @@ static void afs_store_data_success(struct afs_operation *op)
{ {
struct afs_vnode *vnode = op->file[0].vnode; struct afs_vnode *vnode = op->file[0].vnode;
op->ctime = op->file[0].scb.status.mtime_client;
afs_vnode_commit_status(op, &op->file[0]); afs_vnode_commit_status(op, &op->file[0]);
if (op->error == 0) { if (op->error == 0) {
afs_pages_written_back(vnode, op->store.first, op->store.last); afs_pages_written_back(vnode, op->store.first, op->store.last);
...@@ -491,6 +492,7 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, ...@@ -491,6 +492,7 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
unsigned long count, priv; unsigned long count, priv;
unsigned n, offset, to, f, t; unsigned n, offset, to, f, t;
pgoff_t start, first, last; pgoff_t start, first, last;
loff_t i_size, end;
int loop, ret; int loop, ret;
_enter(",%lx", primary_page->index); _enter(",%lx", primary_page->index);
...@@ -591,7 +593,12 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, ...@@ -591,7 +593,12 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
first = primary_page->index; first = primary_page->index;
last = first + count - 1; last = first + count - 1;
end = (loff_t)last * PAGE_SIZE + to;
i_size = i_size_read(&vnode->vfs_inode);
_debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to); _debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to);
if (end > i_size)
to = i_size & ~PAGE_MASK;
ret = afs_store_data(mapping, first, last, offset, to); ret = afs_store_data(mapping, first, last, offset, to);
switch (ret) { switch (ret) {
...@@ -844,6 +851,7 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf) ...@@ -844,6 +851,7 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
vmf->page->index, priv); vmf->page->index, priv);
SetPagePrivate(vmf->page); SetPagePrivate(vmf->page);
set_page_private(vmf->page, priv); set_page_private(vmf->page, priv);
file_update_time(file);
sb_end_pagefault(inode->i_sb); sb_end_pagefault(inode->i_sb);
return VM_FAULT_LOCKED; return VM_FAULT_LOCKED;
......
...@@ -329,29 +329,6 @@ static void xdr_decode_YFSFetchVolumeStatus(const __be32 **_bp, ...@@ -329,29 +329,6 @@ static void xdr_decode_YFSFetchVolumeStatus(const __be32 **_bp,
*_bp += sizeof(*x) / sizeof(__be32); *_bp += sizeof(*x) / sizeof(__be32);
} }
/*
* Deliver a reply that's a status, callback and volsync.
*/
static int yfs_deliver_fs_status_cb_and_volsync(struct afs_call *call)
{
struct afs_operation *op = call->op;
const __be32 *bp;
int ret;
ret = afs_transfer_reply(call);
if (ret < 0)
return ret;
/* unmarshall the reply once we've received all of it */
bp = call->buffer;
xdr_decode_YFSFetchStatus(&bp, call, &op->file[0].scb);
xdr_decode_YFSCallBack(&bp, call, &op->file[0].scb);
xdr_decode_YFSVolSync(&bp, &op->volsync);
_leave(" = 0 [done]");
return 0;
}
/* /*
* Deliver reply data to operations that just return a file status and a volume * Deliver reply data to operations that just return a file status and a volume
* sync record. * sync record.
...@@ -374,48 +351,6 @@ static int yfs_deliver_status_and_volsync(struct afs_call *call) ...@@ -374,48 +351,6 @@ static int yfs_deliver_status_and_volsync(struct afs_call *call)
return 0; return 0;
} }
/*
* YFS.FetchStatus operation type
*/
static const struct afs_call_type yfs_RXYFSFetchStatus_vnode = {
.name = "YFS.FetchStatus(vnode)",
.op = yfs_FS_FetchStatus,
.deliver = yfs_deliver_fs_status_cb_and_volsync,
.destructor = afs_flat_call_destructor,
};
/*
* Fetch the status information for a file.
*/
void yfs_fs_fetch_file_status(struct afs_operation *op)
{
struct afs_vnode_param *vp = &op->file[0];
struct afs_call *call;
__be32 *bp;
_enter(",%x,{%llx:%llu},,",
key_serial(op->key), vp->fid.vid, vp->fid.vnode);
call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchStatus_vnode,
sizeof(__be32) * 2 +
sizeof(struct yfs_xdr_YFSFid),
sizeof(struct yfs_xdr_YFSFetchStatus) +
sizeof(struct yfs_xdr_YFSCallBack) +
sizeof(struct yfs_xdr_YFSVolSync));
if (!call)
return afs_op_nomem(op);
/* marshall the parameters */
bp = call->request;
bp = xdr_encode_u32(bp, YFSFETCHSTATUS);
bp = xdr_encode_u32(bp, 0); /* RPC flags */
bp = xdr_encode_YFSFid(bp, &vp->fid);
yfs_check_req(call, bp);
trace_afs_make_fs_call(call, &vp->fid);
afs_make_op_call(op, call, GFP_NOFS);
}
/* /*
* Deliver reply data to an YFS.FetchData64. * Deliver reply data to an YFS.FetchData64.
*/ */
...@@ -1604,13 +1539,37 @@ void yfs_fs_release_lock(struct afs_operation *op) ...@@ -1604,13 +1539,37 @@ void yfs_fs_release_lock(struct afs_operation *op)
afs_make_op_call(op, call, GFP_NOFS); afs_make_op_call(op, call, GFP_NOFS);
} }
/*
* Deliver a reply to YFS.FetchStatus
*/
static int yfs_deliver_fs_fetch_status(struct afs_call *call)
{
struct afs_operation *op = call->op;
struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
const __be32 *bp;
int ret;
ret = afs_transfer_reply(call);
if (ret < 0)
return ret;
/* unmarshall the reply once we've received all of it */
bp = call->buffer;
xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
xdr_decode_YFSCallBack(&bp, call, &vp->scb);
xdr_decode_YFSVolSync(&bp, &op->volsync);
_leave(" = 0 [done]");
return 0;
}
/* /*
* YFS.FetchStatus operation type * YFS.FetchStatus operation type
*/ */
static const struct afs_call_type yfs_RXYFSFetchStatus = { static const struct afs_call_type yfs_RXYFSFetchStatus = {
.name = "YFS.FetchStatus", .name = "YFS.FetchStatus",
.op = yfs_FS_FetchStatus, .op = yfs_FS_FetchStatus,
.deliver = yfs_deliver_fs_status_cb_and_volsync, .deliver = yfs_deliver_fs_fetch_status,
.destructor = afs_flat_call_destructor, .destructor = afs_flat_call_destructor,
}; };
...@@ -1619,7 +1578,7 @@ static const struct afs_call_type yfs_RXYFSFetchStatus = { ...@@ -1619,7 +1578,7 @@ static const struct afs_call_type yfs_RXYFSFetchStatus = {
*/ */
void yfs_fs_fetch_status(struct afs_operation *op) void yfs_fs_fetch_status(struct afs_operation *op)
{ {
struct afs_vnode_param *vp = &op->file[0]; struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
struct afs_call *call; struct afs_call *call;
__be32 *bp; __be32 *bp;
......
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