NFS: Optimise attribute revalidation on close().
[linux-2.6-block.git] / fs / nfs / nfs4proc.c
index ff378126ccd768fc39710f16a0eab0483156990c..f363fd6c7f4db7acaa1491d12ff4c544005b4478 100644 (file)
@@ -187,8 +187,11 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf
 {
        struct nfs_inode *nfsi = NFS_I(inode);
 
+       spin_lock(&inode->i_lock);
+       nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
        if (cinfo->before == nfsi->change_attr && cinfo->atomic)
                nfsi->change_attr = cinfo->after;
+       spin_unlock(&inode->i_lock);
 }
 
 /* Helper for asynchronous RPC calls */
@@ -212,6 +215,7 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid,
 
        open_flags &= (FMODE_READ|FMODE_WRITE);
        /* Protect against nfs4_find_state() */
+       spin_lock(&state->owner->so_lock);
        spin_lock(&inode->i_lock);
        state->state |= open_flags;
        /* NB! List reordering - see the reclaim code for why.  */
@@ -221,6 +225,7 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid,
                state->nreaders++;
        memcpy(&state->stateid, stateid, sizeof(state->stateid));
        spin_unlock(&inode->i_lock);
+       spin_unlock(&state->owner->so_lock);
 }
 
 /*
@@ -438,7 +443,11 @@ static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner  *sp, stru
        nfs_increment_open_seqid(status, o_arg->seqid);
        if (status != 0)
                goto out;
-       update_changeattr(dir, &o_res->cinfo);
+       if (o_arg->open_flags & O_CREAT) {
+               update_changeattr(dir, &o_res->cinfo);
+               nfs_post_op_update_inode(dir, o_res->dir_attr);
+       } else
+               nfs_refresh_inode(dir, o_res->dir_attr);
        if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
                status = _nfs4_proc_open_confirm(server->client, &o_res->fh,
                                sp, &o_res->stateid, o_arg->seqid);
@@ -492,9 +501,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
        struct inode *inode = state->inode;
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs_delegation *delegation = NFS_I(inode)->delegation;
-       struct nfs_fattr        f_attr = {
-               .valid = 0,
-       };
+       struct nfs_fattr f_attr, dir_attr;
        struct nfs_openargs o_arg = {
                .fh = NFS_FH(dir),
                .open_flags = state->state,
@@ -504,6 +511,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
        };
        struct nfs_openres o_res = {
                .f_attr = &f_attr,
+               .dir_attr = &dir_attr,
                .server = server,
        };
        int status = 0;
@@ -520,6 +528,8 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
        status = -ENOMEM;
        if (o_arg.seqid == NULL)
                goto out;
+       nfs_fattr_init(&f_attr);
+       nfs_fattr_init(&dir_attr);
        status = _nfs4_proc_open(dir, sp, &o_arg, &o_res);
        if (status != 0)
                goto out_nodeleg;
@@ -690,9 +700,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
        struct nfs4_client *clp = server->nfs4_state;
        struct inode *inode = NULL;
        int                     status;
-       struct nfs_fattr        f_attr = {
-               .valid          = 0,
-       };
+       struct nfs_fattr f_attr, dir_attr;
        struct nfs_openargs o_arg = {
                .fh             = NFS_FH(dir),
                .open_flags     = flags,
@@ -703,6 +711,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
        };
        struct nfs_openres o_res = {
                .f_attr         = &f_attr,
+               .dir_attr       = &dir_attr,
                .server         = server,
        };
 
@@ -724,6 +733,8 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
        o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
        if (o_arg.seqid == NULL)
                return -ENOMEM;
+       nfs_fattr_init(&f_attr);
+       nfs_fattr_init(&dir_attr);
        status = _nfs4_proc_open(dir, sp, &o_arg, &o_res);
        if (status != 0)
                goto out_err;
@@ -822,7 +833,7 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
         };
        int status;
 
-        fattr->valid = 0;
+       nfs_fattr_init(fattr);
 
        if (state != NULL) {
                msg.rpc_cred = state->owner->so_cred;
@@ -1105,13 +1116,12 @@ static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh
 static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
                struct nfs_fsinfo *info)
 {
-       struct nfs_fattr *      fattr = info->fattr;
        struct nfs4_lookup_root_arg args = {
                .bitmask = nfs4_fattr_bitmap,
        };
        struct nfs4_lookup_res res = {
                .server = server,
-               .fattr = fattr,
+               .fattr = info->fattr,
                .fh = fhandle,
        };
        struct rpc_message msg = {
@@ -1119,7 +1129,7 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       fattr->valid = 0;
+       nfs_fattr_init(info->fattr);
        return rpc_call_sync(server->client, &msg, 0);
 }
 
@@ -1182,7 +1192,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
                q.len = p - q.name;
 
                do {
-                       fattr->valid = 0;
+                       nfs_fattr_init(fattr);
                        status = nfs4_handle_exception(server,
                                        rpc_call_sync(server->client, &msg, 0),
                                        &exception);
@@ -1219,7 +1229,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_resp = &res,
        };
        
-       fattr->valid = 0;
+       nfs_fattr_init(fattr);
        return rpc_call_sync(server->client, &msg, 0);
 }
 
@@ -1261,7 +1271,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        struct nfs4_state *state;
        int status;
 
-       fattr->valid = 0;
+       nfs_fattr_init(fattr);
        
        cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
        if (IS_ERR(cred))
@@ -1307,7 +1317,7 @@ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
                .rpc_resp = &res,
        };
        
-       fattr->valid = 0;
+       nfs_fattr_init(fattr);
        
        dprintk("NFS call  lookup %s\n", name->name);
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
@@ -1456,7 +1466,7 @@ static int _nfs4_proc_read(struct nfs_read_data *rdata)
        dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
                        (long long) rdata->args.offset);
 
-       fattr->valid = 0;
+       nfs_fattr_init(fattr);
        status = rpc_call_sync(server->client, &msg, flags);
        if (!status)
                renew_lease(server, timestamp);
@@ -1493,7 +1503,7 @@ static int _nfs4_proc_write(struct nfs_write_data *wdata)
        dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
                        (long long) wdata->args.offset);
 
-       fattr->valid = 0;
+       nfs_fattr_init(fattr);
        status = rpc_call_sync(server->client, &msg, rpcflags);
        dprintk("NFS reply write: %d\n", status);
        return status;
@@ -1527,7 +1537,7 @@ static int _nfs4_proc_commit(struct nfs_write_data *cdata)
        dprintk("NFS call  commit %d @ %Ld\n", cdata->args.count,
                        (long long) cdata->args.offset);
 
-       fattr->valid = 0;
+       nfs_fattr_init(fattr);
        status = rpc_call_sync(server->client, &msg, 0);
        dprintk("NFS reply commit: %d\n", status);
        return status;
@@ -1744,6 +1754,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
                struct nfs_fattr *fattr)
 {
        struct nfs_server *server = NFS_SERVER(dir);
+       struct nfs_fattr dir_fattr;
        struct nfs4_create_arg arg = {
                .dir_fh = NFS_FH(dir),
                .server = server,
@@ -1756,6 +1767,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
                .server = server,
                .fh = fhandle,
                .fattr = fattr,
+               .dir_fattr = &dir_fattr,
        };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK],
@@ -1767,11 +1779,13 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
        if (path->len > NFS4_MAXPATHLEN)
                return -ENAMETOOLONG;
        arg.u.symlink = path;
-       fattr->valid = 0;
+       nfs_fattr_init(fattr);
+       nfs_fattr_init(&dir_fattr);
        
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
        if (!status)
                update_changeattr(dir, &res.dir_cinfo);
+       nfs_post_op_update_inode(dir, res.dir_fattr);
        return status;
 }
 
@@ -1795,7 +1809,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 {
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs_fh fhandle;
-       struct nfs_fattr fattr;
+       struct nfs_fattr fattr, dir_fattr;
        struct nfs4_create_arg arg = {
                .dir_fh = NFS_FH(dir),
                .server = server,
@@ -1808,6 +1822,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
                .server = server,
                .fh = &fhandle,
                .fattr = &fattr,
+               .dir_fattr = &dir_fattr,
        };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
@@ -1816,11 +1831,13 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
        };
        int                     status;
 
-       fattr.valid = 0;
+       nfs_fattr_init(&fattr);
+       nfs_fattr_init(&dir_fattr);
        
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
        if (!status) {
                update_changeattr(dir, &res.dir_cinfo);
+               nfs_post_op_update_inode(dir, res.dir_fattr);
                status = nfs_instantiate(dentry, &fhandle, &fattr);
        }
        return status;
@@ -1893,7 +1910,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 {
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs_fh fh;
-       struct nfs_fattr fattr;
+       struct nfs_fattr fattr, dir_fattr;
        struct nfs4_create_arg arg = {
                .dir_fh = NFS_FH(dir),
                .server = server,
@@ -1905,6 +1922,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
                .server = server,
                .fh = &fh,
                .fattr = &fattr,
+               .dir_fattr = &dir_fattr,
        };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
@@ -1914,7 +1932,8 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
        int                     status;
        int                     mode = sattr->ia_mode;
 
-       fattr.valid = 0;
+       nfs_fattr_init(&fattr);
+       nfs_fattr_init(&dir_fattr);
 
        BUG_ON(!(sattr->ia_valid & ATTR_MODE));
        BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
@@ -1936,6 +1955,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
        if (status == 0) {
                update_changeattr(dir, &res.dir_cinfo);
+               nfs_post_op_update_inode(dir, res.dir_fattr);
                status = nfs_instantiate(dentry, &fh, &fattr);
        }
        return status;
@@ -1967,7 +1987,7 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_resp = fsstat,
        };
 
-       fsstat->fattr->valid = 0;
+       nfs_fattr_init(fsstat->fattr);
        return rpc_call_sync(server->client, &msg, 0);
 }
 
@@ -2014,7 +2034,7 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, str
 
 static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
 {
-       fsinfo->fattr->valid = 0;
+       nfs_fattr_init(fsinfo->fattr);
        return nfs4_do_fsinfo(server, fhandle, fsinfo);
 }
 
@@ -2037,7 +2057,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle
                return 0;
        }
 
-       pathconf->fattr->valid = 0;
+       nfs_fattr_init(pathconf->fattr);
        return rpc_call_sync(server->client, &msg, 0);
 }
 
@@ -2357,7 +2377,7 @@ static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size
                        return -ENOMEM;
                args.acl_pages[0] = localpage;
                args.acl_pgbase = 0;
-               args.acl_len = PAGE_SIZE;
+               resp_len = args.acl_len = PAGE_SIZE;
        } else {
                resp_buf = buf;
                buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase);