afs: Fix updating of i_blocks on file/dir extension
When an afs file or directory is modified locally such that the total file size is extended, i_blocks needs to be recalculated too. Fix this by making afs_write_end() and afs_edit_dir_add() call afs_set_i_size() rather than setting inode->i_size directly as that also recalculates inode->i_blocks. This can be tested by creating and writing into directories and files and then examining them with du. Without this change, directories show a 4 blocks (they start out at 2048 bytes) and files show 0 blocks; with this change, they should show a number of blocks proportional to the file size rounded up to 1024. Fixes:31143d5d51
("AFS: implement basic file write support") Fixes:63a4681ff3
("afs: Locally edit directory data for mkdir/create/unlink/...") Reported-by: Markus Suvanto <markus.suvanto@gmail.com> Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Marc Dionne <marc.dionne@auristor.com> Tested-by: Markus Suvanto <markus.suvanto@gmail.com> cc: linux-afs@lists.infradead.org Link: https://lore.kernel.org/r/163113612442.352844.11162345591911691150.stgit@warthog.procyon.org.uk/
This commit is contained in:
parent
b537a3c217
commit
9d37e1cab2
|
@ -263,7 +263,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
|
|||
if (b == nr_blocks) {
|
||||
_debug("init %u", b);
|
||||
afs_edit_init_block(meta, block, b);
|
||||
i_size_write(&vnode->vfs_inode, (b + 1) * AFS_DIR_BLOCK_SIZE);
|
||||
afs_set_i_size(vnode, (b + 1) * AFS_DIR_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/* Only lower dir pages have a counter in the header. */
|
||||
|
@ -296,7 +296,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
|
|||
new_directory:
|
||||
afs_edit_init_block(meta, meta, 0);
|
||||
i_size = AFS_DIR_BLOCK_SIZE;
|
||||
i_size_write(&vnode->vfs_inode, i_size);
|
||||
afs_set_i_size(vnode, i_size);
|
||||
slot = AFS_DIR_RESV_BLOCKS0;
|
||||
page = page0;
|
||||
block = meta;
|
||||
|
|
|
@ -53,16 +53,6 @@ static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *paren
|
|||
dump_stack();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the file size and block count. Estimate the number of 512 bytes blocks
|
||||
* used, rounded up to nearest 1K for consistency with other AFS clients.
|
||||
*/
|
||||
static void afs_set_i_size(struct afs_vnode *vnode, u64 size)
|
||||
{
|
||||
i_size_write(&vnode->vfs_inode, size);
|
||||
vnode->vfs_inode.i_blocks = ((size + 1023) >> 10) << 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise an inode from the vnode status.
|
||||
*/
|
||||
|
|
|
@ -1596,6 +1596,16 @@ static inline void afs_update_dentry_version(struct afs_operation *op,
|
|||
(void *)(unsigned long)dir_vp->scb.status.data_version;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the file size and block count. Estimate the number of 512 bytes blocks
|
||||
* used, rounded up to nearest 1K for consistency with other AFS clients.
|
||||
*/
|
||||
static inline void afs_set_i_size(struct afs_vnode *vnode, u64 size)
|
||||
{
|
||||
i_size_write(&vnode->vfs_inode, size);
|
||||
vnode->vfs_inode.i_blocks = ((size + 1023) >> 10) << 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
|
|
@ -137,7 +137,7 @@ int afs_write_end(struct file *file, struct address_space *mapping,
|
|||
write_seqlock(&vnode->cb_lock);
|
||||
i_size = i_size_read(&vnode->vfs_inode);
|
||||
if (maybe_i_size > i_size)
|
||||
i_size_write(&vnode->vfs_inode, maybe_i_size);
|
||||
afs_set_i_size(vnode, maybe_i_size);
|
||||
write_sequnlock(&vnode->cb_lock);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue