cifs: fix allocation size on newly created files
authorSteve French <stfrench@microsoft.com>
Fri, 19 Mar 2021 05:05:48 +0000 (00:05 -0500)
committerSteve French <stfrench@microsoft.com>
Fri, 19 Mar 2021 16:51:31 +0000 (11:51 -0500)
Applications that create and extend and write to a file do not
expect to see 0 allocation size.  When file is extended,
set its allocation size to a plausible value until we have a
chance to query the server for it.  When the file is cached
this will prevent showing an impossible number of allocated
blocks (like 0).  This fixes e.g. xfstests 614 which does

    1) create a file and set its size to 64K
    2) mmap write 64K to the file
    3) stat -c %b for the file (to query the number of allocated blocks)

It was failing because we returned 0 blocks.  Even though we would
return the correct cached file size, we returned an impossible
allocation size.

Signed-off-by: Steve French <stfrench@microsoft.com>
CC: <stable@vger.kernel.org>
Reviewed-by: Aurelien Aptel <aaptel@suse.com>
fs/cifs/inode.c

index 7c61bc9573c02b5b4edf6d859360656bd06f4da9..f2df4422e54ae0c8262860165a93a8d96df229e2 100644 (file)
@@ -2395,7 +2395,7 @@ int cifs_getattr(struct user_namespace *mnt_userns, const struct path *path,
         * We need to be sure that all dirty pages are written and the server
         * has actual ctime, mtime and file length.
         */
-       if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE)) &&
+       if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE | STATX_BLOCKS)) &&
            !CIFS_CACHE_READ(CIFS_I(inode)) &&
            inode->i_mapping && inode->i_mapping->nrpages != 0) {
                rc = filemap_fdatawait(inode->i_mapping);
@@ -2585,6 +2585,14 @@ set_size_out:
        if (rc == 0) {
                cifsInode->server_eof = attrs->ia_size;
                cifs_setsize(inode, attrs->ia_size);
+               /*
+                * i_blocks is not related to (i_size / i_blksize), but instead
+                * 512 byte (2**9) size is required for calculating num blocks.
+                * Until we can query the server for actual allocation size,
+                * this is best estimate we have for blocks allocated for a file
+                * Number of blocks must be rounded up so size 1 is not 0 blocks
+                */
+               inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9;
 
                /*
                 * The man page of truncate says if the size changed,