Skip to content

Commit 0770bd4

Browse files
committed
afs: Skip truncation on the server of data we haven't written yet
Don't send a truncation RPC to the server if we're only shortening data that's in the pagecache and is beyond the server's EOF. Also don't automatically force writeback on setattr, but do wait to store RPCs that are in the region to be removed on a shortening truncation. Signed-off-by: David Howells <[email protected]> Tested-by: [email protected] Acked-by: Jeff Layton <[email protected]> cc: Marc Dionne <[email protected]> cc: [email protected] Link: https://lore.kernel.org/r/163819663275.215744.4781075713714590913.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/163906972600.143852.14237659724463048094.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/163967177522.1823006.15336589054269480601.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/164021571880.640689.1837025861707111004.stgit@warthog.procyon.org.uk/ # v4
1 parent c7f75ef commit 0770bd4

File tree

1 file changed

+35
-10
lines changed

1 file changed

+35
-10
lines changed

fs/afs/inode.c

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -848,42 +848,67 @@ static const struct afs_operation_ops afs_setattr_operation = {
848848
int afs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
849849
struct iattr *attr)
850850
{
851+
const unsigned int supported =
852+
ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
853+
ATTR_MTIME | ATTR_MTIME_SET | ATTR_TIMES_SET | ATTR_TOUCH;
851854
struct afs_operation *op;
852855
struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
856+
struct inode *inode = &vnode->vfs_inode;
857+
loff_t i_size;
853858
int ret;
854859

855860
_enter("{%llx:%llu},{n=%pd},%x",
856861
vnode->fid.vid, vnode->fid.vnode, dentry,
857862
attr->ia_valid);
858863

859-
if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
860-
ATTR_MTIME | ATTR_MTIME_SET | ATTR_TIMES_SET |
861-
ATTR_TOUCH))) {
864+
if (!(attr->ia_valid & supported)) {
862865
_leave(" = 0 [unsupported]");
863866
return 0;
864867
}
865868

869+
i_size = i_size_read(inode);
866870
if (attr->ia_valid & ATTR_SIZE) {
867-
if (!S_ISREG(vnode->vfs_inode.i_mode))
871+
if (!S_ISREG(inode->i_mode))
868872
return -EISDIR;
869873

870-
ret = inode_newsize_ok(&vnode->vfs_inode, attr->ia_size);
874+
ret = inode_newsize_ok(inode, attr->ia_size);
871875
if (ret)
872876
return ret;
873877

874-
if (attr->ia_size == i_size_read(&vnode->vfs_inode))
878+
if (attr->ia_size == i_size)
875879
attr->ia_valid &= ~ATTR_SIZE;
876880
}
877881

878882
fscache_use_cookie(afs_vnode_cache(vnode), true);
879883

880-
/* flush any dirty data outstanding on a regular file */
881-
if (S_ISREG(vnode->vfs_inode.i_mode))
882-
filemap_write_and_wait(vnode->vfs_inode.i_mapping);
883-
884884
/* Prevent any new writebacks from starting whilst we do this. */
885885
down_write(&vnode->validate_lock);
886886

887+
if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode)) {
888+
loff_t size = attr->ia_size;
889+
890+
/* Wait for any outstanding writes to the server to complete */
891+
loff_t from = min(size, i_size);
892+
loff_t to = max(size, i_size);
893+
ret = filemap_fdatawait_range(inode->i_mapping, from, to);
894+
if (ret < 0)
895+
goto out_unlock;
896+
897+
/* Don't talk to the server if we're just shortening in-memory
898+
* writes that haven't gone to the server yet.
899+
*/
900+
if (!(attr->ia_valid & (supported & ~ATTR_SIZE & ~ATTR_MTIME)) &&
901+
attr->ia_size < i_size &&
902+
attr->ia_size > vnode->status.size) {
903+
truncate_pagecache(inode, attr->ia_size);
904+
fscache_resize_cookie(afs_vnode_cache(vnode),
905+
attr->ia_size);
906+
i_size_write(inode, attr->ia_size);
907+
ret = 0;
908+
goto out_unlock;
909+
}
910+
}
911+
887912
op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ?
888913
afs_file_key(attr->ia_file) : NULL),
889914
vnode->volume);

0 commit comments

Comments
 (0)