NFSv4.1: Don't trust attributes if a pNFS LAYOUTCOMMIT is outstanding
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 13 Jan 2014 17:08:11 +0000 (12:08 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 13 Jan 2014 17:08:11 +0000 (12:08 -0500)
If a LAYOUTCOMMIT is outstanding, then chances are that the metadata
server may still be returning incorrect values for the change attribute,
ctime, mtime and/or size.
Just ignore those attributes for now, and wait for the LAYOUTCOMMIT
rpc call to finish.

Reported-by: shaobingqing <shaobingqing@bwstor.com.cn>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/inode.c
fs/nfs/nfs4proc.c
fs/nfs/pnfs.h

index 5feec233895d51e2ca0069a62cb14a852855b531..c63e152244665990ce20603c8658ec87119f74a1 100644 (file)
@@ -1283,12 +1283,28 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
                ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
 }
 
+/*
+ * Don't trust the change_attribute, mtime, ctime or size if
+ * a pnfs LAYOUTCOMMIT is outstanding
+ */
+static void nfs_inode_attrs_handle_layoutcommit(struct inode *inode,
+               struct nfs_fattr *fattr)
+{
+       if (pnfs_layoutcommit_outstanding(inode))
+               fattr->valid &= ~(NFS_ATTR_FATTR_CHANGE |
+                               NFS_ATTR_FATTR_MTIME |
+                               NFS_ATTR_FATTR_CTIME |
+                               NFS_ATTR_FATTR_SIZE);
+}
+
 static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
 {
        int ret;
 
        trace_nfs_refresh_inode_enter(inode);
 
+       nfs_inode_attrs_handle_layoutcommit(inode, fattr);
+
        if (nfs_inode_attrs_need_update(inode, fattr))
                ret = nfs_update_inode(inode, fattr);
        else
@@ -1518,8 +1534,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                if (new_isize != cur_isize) {
                        /* Do we perhaps have any outstanding writes, or has
                         * the file grown beyond our last write? */
-                       if ((nfsi->npages == 0 && !test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) ||
-                            new_isize > cur_isize) {
+                       if ((nfsi->npages == 0) || new_isize > cur_isize) {
                                i_size_write(inode, new_isize);
                                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
                        }
index 15052b81df4245e4f797adb0d0b2e523338b23cc..f4908eb40a21e4f82af27f481ba3bea701a88ec3 100644 (file)
@@ -7780,10 +7780,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
        case -NFS4ERR_BADLAYOUT:     /* no layout */
        case -NFS4ERR_GRACE:        /* loca_recalim always false */
                task->tk_status = 0;
-               break;
        case 0:
-               nfs_post_op_update_inode_force_wcc(data->args.inode,
-                                                  data->res.fattr);
                break;
        default:
                if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
@@ -7798,6 +7795,8 @@ static void nfs4_layoutcommit_release(void *calldata)
        struct nfs4_layoutcommit_data *data = calldata;
 
        pnfs_cleanup_layoutcommit(data);
+       nfs_post_op_update_inode_force_wcc(data->args.inode,
+                                          data->res.fattr);
        put_rpccred(data->cred);
        kfree(data);
 }
index a4f41810a7f497fbe5b34d497d8c1a5078a44524..023793909778ef975b3441d19b8d8632845bc2c4 100644 (file)
@@ -359,6 +359,15 @@ pnfs_ld_layoutret_on_setattr(struct inode *inode)
                PNFS_LAYOUTRET_ON_SETATTR;
 }
 
+static inline bool
+pnfs_layoutcommit_outstanding(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       return test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags) != 0 ||
+               test_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags) != 0;
+}
+
 static inline int pnfs_return_layout(struct inode *ino)
 {
        struct nfs_inode *nfsi = NFS_I(ino);
@@ -515,6 +524,13 @@ pnfs_use_threshold(struct nfs4_threshold **dst, struct nfs4_threshold *src,
        return false;
 }
 
+static inline bool
+pnfs_layoutcommit_outstanding(struct inode *inode)
+{
+       return false;
+}
+
+
 static inline struct nfs4_threshold *pnfs_mdsthreshold_alloc(void)
 {
        return NULL;