ceph: update the mtime when truncating up
authorJeff Layton <jlayton@kernel.org>
Thu, 25 Jul 2019 17:03:32 +0000 (13:03 -0400)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 16 Sep 2019 10:06:24 +0000 (12:06 +0200)
If we have Fx caps, and the we're truncating the size to be larger, then
we'll cache the size attribute change, but the mtime won't be updated.

Move the size handling before the mtime, and add ATTR_MTIME to ia_valid
in that case to make sure the mtime also gets updated.

This fixes xfstest generic/313.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/inode.c

index 332433b490f5ab52e9fa35231519ee3cfc6d80db..9f135624ae476a23ab610cff33d173646e111724 100644 (file)
@@ -1989,7 +1989,7 @@ static const struct inode_operations ceph_symlink_iops = {
 int __ceph_setattr(struct inode *inode, struct iattr *attr)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       const unsigned int ia_valid = attr->ia_valid;
+       unsigned int ia_valid = attr->ia_valid;
        struct ceph_mds_request *req;
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_cap_flush *prealloc_cf;
@@ -2094,6 +2094,26 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
                                   CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR;
                }
        }
+       if (ia_valid & ATTR_SIZE) {
+               dout("setattr %p size %lld -> %lld\n", inode,
+                    inode->i_size, attr->ia_size);
+               if ((issued & CEPH_CAP_FILE_EXCL) &&
+                   attr->ia_size > inode->i_size) {
+                       i_size_write(inode, attr->ia_size);
+                       inode->i_blocks = calc_inode_blocks(attr->ia_size);
+                       ci->i_reported_size = attr->ia_size;
+                       dirtied |= CEPH_CAP_FILE_EXCL;
+                       ia_valid |= ATTR_MTIME;
+               } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
+                          attr->ia_size != inode->i_size) {
+                       req->r_args.setattr.size = cpu_to_le64(attr->ia_size);
+                       req->r_args.setattr.old_size =
+                               cpu_to_le64(inode->i_size);
+                       mask |= CEPH_SETATTR_SIZE;
+                       release |= CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL |
+                                  CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR;
+               }
+       }
        if (ia_valid & ATTR_MTIME) {
                dout("setattr %p mtime %lld.%ld -> %lld.%ld\n", inode,
                     inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
@@ -2116,25 +2136,6 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
                                   CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR;
                }
        }
-       if (ia_valid & ATTR_SIZE) {
-               dout("setattr %p size %lld -> %lld\n", inode,
-                    inode->i_size, attr->ia_size);
-               if ((issued & CEPH_CAP_FILE_EXCL) &&
-                   attr->ia_size > inode->i_size) {
-                       i_size_write(inode, attr->ia_size);
-                       inode->i_blocks = calc_inode_blocks(attr->ia_size);
-                       ci->i_reported_size = attr->ia_size;
-                       dirtied |= CEPH_CAP_FILE_EXCL;
-               } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
-                          attr->ia_size != inode->i_size) {
-                       req->r_args.setattr.size = cpu_to_le64(attr->ia_size);
-                       req->r_args.setattr.old_size =
-                               cpu_to_le64(inode->i_size);
-                       mask |= CEPH_SETATTR_SIZE;
-                       release |= CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL |
-                                  CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR;
-               }
-       }
 
        /* these do nothing */
        if (ia_valid & ATTR_CTIME) {