Merge branch 'for-2.6.36' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 7 Aug 2010 21:24:41 +0000 (14:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 7 Aug 2010 21:24:41 +0000 (14:24 -0700)
* 'for-2.6.36' of git://linux-nfs.org/~bfields/linux: (34 commits)
  nfsd4: fix file open accounting for RDWR opens
  nfsd: don't allow setting maxblksize after svc created
  nfsd: initialize nfsd versions before creating svc
  net: sunrpc: removed duplicated #include
  nfsd41: Fix a crash when a callback is retried
  nfsd: fix startup/shutdown order bug
  nfsd: minor nfsd read api cleanup
  gcc-4.6: nfsd: fix initialized but not read warnings
  nfsd4: share file descriptors between stateid's
  nfsd4: fix openmode checking on IO using lock stateid
  nfsd4: miscellaneous process_open2 cleanup
  nfsd4: don't pretend to support write delegations
  nfsd: bypass readahead cache when have struct file
  nfsd: minor nfsd_svc() cleanup
  nfsd: move more into nfsd_startup()
  nfsd: just keep single lockd reference for nfsd
  nfsd: clean up nfsd_create_serv error handling
  nfsd: fix error handling in __write_ports_addxprt
  nfsd: fix error handling when starting nfsd with rpcbind down
  nfsd4: fix v4 state shutdown error paths
  ...

14 files changed:
fs/nfsd/nfs3proc.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/nfsproc.c
fs/nfsd/nfssvc.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nfsd/vfs.h
include/linux/sunrpc/cache.h
net/sunrpc/cache.c
net/sunrpc/sunrpc_syms.c

index 3d68f45a37b931027ef1e5e729305a4f7645fcf5..5b7e3021e06b874e6d4e802dae08164b39906485 100644 (file)
@@ -168,7 +168,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
        svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
 
        fh_copy(&resp->fh, &argp->fh);
-       nfserr = nfsd_read(rqstp, &resp->fh, NULL,
+       nfserr = nfsd_read(rqstp, &resp->fh,
                                  argp->offset,
                                  rqstp->rq_vec, argp->vlen,
                                  &resp->count);
@@ -271,7 +271,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
        fh_init(&resp->fh, NFS3_FHSIZE);
        nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
                                    &argp->attrs, S_IFDIR, 0, &resp->fh);
-
+       fh_unlock(&resp->dirfh);
        RETURN_STATUS(nfserr);
 }
 
@@ -327,7 +327,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
        type = nfs3_ftypes[argp->ftype];
        nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
                                    &argp->attrs, type, rdev, &resp->fh);
-
+       fh_unlock(&resp->dirfh);
        RETURN_STATUS(nfserr);
 }
 
@@ -348,6 +348,7 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
        /* Unlink. -S_IFDIR means file must not be a directory */
        fh_copy(&resp->fh, &argp->fh);
        nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
+       fh_unlock(&resp->fh);
        RETURN_STATUS(nfserr);
 }
 
@@ -367,6 +368,7 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
 
        fh_copy(&resp->fh, &argp->fh);
        nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
+       fh_unlock(&resp->fh);
        RETURN_STATUS(nfserr);
 }
 
index eb78e7e2207740c5a3cf36e4d098ef970c88be73..988cbb3a19b6785378a5dcaab1118e4b3d78b14b 100644 (file)
@@ -143,8 +143,6 @@ struct nfs4_cb_compound_hdr {
        u32             minorversion;
        /* res */
        int             status;
-       u32             taglen;
-       char            *tag;
 };
 
 static struct {
@@ -204,6 +202,16 @@ nfs_cb_stat_to_errno(int stat)
  * XDR encode
  */
 
+static void
+encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
+{
+       __be32 *p;
+
+       RESERVE_SPACE(sizeof(stateid_t));
+       WRITE32(sid->si_generation);
+       WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
+}
+
 static void
 encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
 {
@@ -229,10 +237,10 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp,
        __be32 *p;
        int len = dp->dl_fh.fh_size;
 
-       RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len);
+       RESERVE_SPACE(4);
        WRITE32(OP_CB_RECALL);
-       WRITE32(dp->dl_stateid.si_generation);
-       WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t));
+       encode_stateid(xdr, &dp->dl_stateid);
+       RESERVE_SPACE(8 + (XDR_QUADLEN(len) << 2));
        WRITE32(0); /* truncate optimization not implemented */
        WRITE32(len);
        WRITEMEM(&dp->dl_fh.fh_base, len);
@@ -293,13 +301,14 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p,
 static int
 decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
         __be32 *p;
+       u32 taglen;
 
         READ_BUF(8);
         READ32(hdr->status);
-        READ32(hdr->taglen);
-        READ_BUF(hdr->taglen + 4);
-        hdr->tag = (char *)p;
-        p += XDR_QUADLEN(hdr->taglen);
+       /* We've got no use for the tag; ignore it: */
+        READ32(taglen);
+        READ_BUF(taglen + 4);
+        p += XDR_QUADLEN(taglen);
         READ32(hdr->nops);
         return 0;
 }
@@ -667,28 +676,28 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
        }
 
        switch (task->tk_status) {
-       case -EIO:
+       case 0:
+               return;
+       case -EBADHANDLE:
+       case -NFS4ERR_BAD_STATEID:
+               /* Race: client probably got cb_recall
+                * before open reply granting delegation */
+               break;
+       default:
                /* Network partition? */
                atomic_set(&clp->cl_cb_set, 0);
                warn_no_callback_path(clp, task->tk_status);
                if (current_rpc_client != task->tk_client) {
                        /* queue a callback on the new connection: */
+                       atomic_inc(&dp->dl_count);
                        nfsd4_cb_recall(dp);
                        return;
                }
-       case -EBADHANDLE:
-       case -NFS4ERR_BAD_STATEID:
-               /* Race: client probably got cb_recall
-                * before open reply granting delegation */
-               break;
-       default:
-               /* success, or error we can't handle */
-               return;
        }
        if (dp->dl_retries--) {
                rpc_delay(task, 2*HZ);
                task->tk_status = 0;
-               rpc_restart_call(task);
+               rpc_restart_call_prepare(task);
                return;
        } else {
                atomic_set(&clp->cl_cb_set, 0);
@@ -752,18 +761,16 @@ static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
                .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
                .rpc_cred = callback_cred
        };
-       int status;
 
-       if (clnt == NULL)
+       if (clnt == NULL) {
+               nfs4_put_delegation(dp);
                return; /* Client is shutting down; give up. */
+       }
 
        args->args_op = dp;
        msg.rpc_argp = args;
        dp->dl_retries = 1;
-       status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT,
-                               &nfsd4_cb_recall_ops, dp);
-       if (status)
-               nfs4_put_delegation(dp);
+       rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp);
 }
 
 void nfsd4_do_callback_rpc(struct work_struct *w)
index 4a2734758778117a92a16163644a11606cb7d602..2e7357104cfdf3208a6abe357c91e92536d8e815 100644 (file)
@@ -51,7 +51,6 @@ static time_t boot_time;
 static u32 current_ownerid = 1;
 static u32 current_fileid = 1;
 static u32 current_delegid = 1;
-static u32 nfs4_init;
 static stateid_t zerostateid;             /* bits all 0 */
 static stateid_t onestateid;              /* bits all 1 */
 static u64 current_sessionid = 1;
@@ -163,6 +162,46 @@ static struct list_head    ownerstr_hashtbl[OWNER_HASH_SIZE];
 static struct list_head file_hashtbl[FILE_HASH_SIZE];
 static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
 
+static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
+{
+       BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
+       atomic_inc(&fp->fi_access[oflag]);
+}
+
+static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
+{
+       if (oflag == O_RDWR) {
+               __nfs4_file_get_access(fp, O_RDONLY);
+               __nfs4_file_get_access(fp, O_WRONLY);
+       } else
+               __nfs4_file_get_access(fp, oflag);
+}
+
+static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
+{
+       if (fp->fi_fds[oflag]) {
+               fput(fp->fi_fds[oflag]);
+               fp->fi_fds[oflag] = NULL;
+       }
+}
+
+static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
+{
+       if (atomic_dec_and_test(&fp->fi_access[oflag])) {
+               nfs4_file_put_fd(fp, O_RDWR);
+               nfs4_file_put_fd(fp, oflag);
+       }
+}
+
+static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
+{
+       if (oflag == O_RDWR) {
+               __nfs4_file_put_access(fp, O_RDONLY);
+               __nfs4_file_put_access(fp, O_WRONLY);
+       } else
+               __nfs4_file_put_access(fp, oflag);
+}
+
 static struct nfs4_delegation *
 alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
 {
@@ -171,6 +210,13 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn;
 
        dprintk("NFSD alloc_init_deleg\n");
+       /*
+        * Major work on the lease subsystem (for example, to support
+        * calbacks on stat) will be required before we can support
+        * write delegations properly.
+        */
+       if (type != NFS4_OPEN_DELEGATE_READ)
+               return NULL;
        if (fp->fi_had_conflict)
                return NULL;
        if (num_delegations > max_delegations)
@@ -185,9 +231,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        dp->dl_client = clp;
        get_nfs4_file(fp);
        dp->dl_file = fp;
+       nfs4_file_get_access(fp, O_RDONLY);
        dp->dl_flock = NULL;
-       get_file(stp->st_vfs_file);
-       dp->dl_vfs_file = stp->st_vfs_file;
        dp->dl_type = type;
        dp->dl_ident = cb->cb_ident;
        dp->dl_stateid.si_boot = boot_time;
@@ -222,15 +267,12 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
 static void
 nfs4_close_delegation(struct nfs4_delegation *dp)
 {
-       struct file *filp = dp->dl_vfs_file;
+       struct file *filp = find_readable_file(dp->dl_file);
 
        dprintk("NFSD: close_delegation dp %p\n",dp);
-       dp->dl_vfs_file = NULL;
-       /* The following nfsd_close may not actually close the file,
-        * but we want to remove the lease in any case. */
        if (dp->dl_flock)
                vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
-       nfsd_close(filp);
+       nfs4_file_put_access(dp->dl_file, O_RDONLY);
 }
 
 /* Called under the state lock. */
@@ -302,8 +344,12 @@ static void free_generic_stateid(struct nfs4_stateid *stp)
 
 static void release_lock_stateid(struct nfs4_stateid *stp)
 {
+       struct file *file;
+
        unhash_generic_stateid(stp);
-       locks_remove_posix(stp->st_vfs_file, (fl_owner_t)stp->st_stateowner);
+       file = find_any_file(stp->st_file);
+       if (file)
+               locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
        free_generic_stateid(stp);
 }
 
@@ -341,11 +387,85 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp)
        }
 }
 
+/*
+ * We store the NONE, READ, WRITE, and BOTH bits separately in the
+ * st_{access,deny}_bmap field of the stateid, in order to track not
+ * only what share bits are currently in force, but also what
+ * combinations of share bits previous opens have used.  This allows us
+ * to enforce the recommendation of rfc 3530 14.2.19 that the server
+ * return an error if the client attempt to downgrade to a combination
+ * of share bits not explicable by closing some of its previous opens.
+ *
+ * XXX: This enforcement is actually incomplete, since we don't keep
+ * track of access/deny bit combinations; so, e.g., we allow:
+ *
+ *     OPEN allow read, deny write
+ *     OPEN allow both, deny none
+ *     DOWNGRADE allow read, deny none
+ *
+ * which we should reject.
+ */
+static void
+set_access(unsigned int *access, unsigned long bmap) {
+       int i;
+
+       *access = 0;
+       for (i = 1; i < 4; i++) {
+               if (test_bit(i, &bmap))
+                       *access |= i;
+       }
+}
+
+static void
+set_deny(unsigned int *deny, unsigned long bmap) {
+       int i;
+
+       *deny = 0;
+       for (i = 0; i < 4; i++) {
+               if (test_bit(i, &bmap))
+                       *deny |= i ;
+       }
+}
+
+static int
+test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
+       unsigned int access, deny;
+
+       set_access(&access, stp->st_access_bmap);
+       set_deny(&deny, stp->st_deny_bmap);
+       if ((access & open->op_share_deny) || (deny & open->op_share_access))
+               return 0;
+       return 1;
+}
+
+static int nfs4_access_to_omode(u32 access)
+{
+       switch (access) {
+       case NFS4_SHARE_ACCESS_READ:
+               return O_RDONLY;
+       case NFS4_SHARE_ACCESS_WRITE:
+               return O_WRONLY;
+       case NFS4_SHARE_ACCESS_BOTH:
+               return O_RDWR;
+       }
+       BUG();
+}
+
+static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp)
+{
+       unsigned int access;
+
+       set_access(&access, stp->st_access_bmap);
+       return nfs4_access_to_omode(access);
+}
+
 static void release_open_stateid(struct nfs4_stateid *stp)
 {
+       int oflag = nfs4_access_bmap_to_omode(stp);
+
        unhash_generic_stateid(stp);
        release_stateid_lockowners(stp);
-       nfsd_close(stp->st_vfs_file);
+       nfs4_file_put_access(stp->st_file, oflag);
        free_generic_stateid(stp);
 }
 
@@ -457,7 +577,7 @@ static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan)
        spin_unlock(&nfsd_drc_lock);
 
        if (fchan->maxreqs == 0)
-               return nfserr_serverfault;
+               return nfserr_jukebox;
 
        fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ;
        return 0;
@@ -542,7 +662,7 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
        BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot)
                     + sizeof(struct nfsd4_session) > PAGE_SIZE);
 
-       status = nfserr_serverfault;
+       status = nfserr_jukebox;
        /* allocate struct nfsd4_session and slot table pointers in one piece */
        slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *);
        new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL);
@@ -591,10 +711,8 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid)
 
        dump_sessionid(__func__, sessionid);
        idx = hash_sessionid(sessionid);
-       dprintk("%s: idx is %d\n", __func__, idx);
        /* Search in the appropriate list */
        list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) {
-               dump_sessionid("list traversal", &elem->se_sessionid);
                if (!memcmp(elem->se_sessionid.data, sessionid->data,
                            NFS4_MAX_SESSIONID_LEN)) {
                        return elem;
@@ -714,7 +832,6 @@ release_session_client(struct nfsd4_session *session)
        } else
                renew_client_locked(clp);
        spin_unlock(&client_lock);
-       nfsd4_put_session(session);
 }
 
 /* must be called under the client_lock */
@@ -1220,7 +1337,7 @@ out_new:
        /* Normal case */
        new = create_client(exid->clname, dname, rqstp, &verf);
        if (new == NULL) {
-               status = nfserr_serverfault;
+               status = nfserr_jukebox;
                goto out;
        }
 
@@ -1760,6 +1877,8 @@ alloc_init_file(struct inode *ino)
                fp->fi_inode = igrab(ino);
                fp->fi_id = current_fileid++;
                fp->fi_had_conflict = false;
+               memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
+               memset(fp->fi_access, 0, sizeof(fp->fi_access));
                spin_lock(&recall_lock);
                list_add(&fp->fi_hash, &file_hashtbl[hashval]);
                spin_unlock(&recall_lock);
@@ -1970,57 +2089,6 @@ static inline int deny_valid(u32 x)
        return x <= NFS4_SHARE_DENY_BOTH;
 }
 
-/*
- * We store the NONE, READ, WRITE, and BOTH bits separately in the
- * st_{access,deny}_bmap field of the stateid, in order to track not
- * only what share bits are currently in force, but also what
- * combinations of share bits previous opens have used.  This allows us
- * to enforce the recommendation of rfc 3530 14.2.19 that the server
- * return an error if the client attempt to downgrade to a combination
- * of share bits not explicable by closing some of its previous opens.
- *
- * XXX: This enforcement is actually incomplete, since we don't keep
- * track of access/deny bit combinations; so, e.g., we allow:
- *
- *     OPEN allow read, deny write
- *     OPEN allow both, deny none
- *     DOWNGRADE allow read, deny none
- *
- * which we should reject.
- */
-static void
-set_access(unsigned int *access, unsigned long bmap) {
-       int i;
-
-       *access = 0;
-       for (i = 1; i < 4; i++) {
-               if (test_bit(i, &bmap))
-                       *access |= i;
-       }
-}
-
-static void
-set_deny(unsigned int *deny, unsigned long bmap) {
-       int i;
-
-       *deny = 0;
-       for (i = 0; i < 4; i++) {
-               if (test_bit(i, &bmap))
-                       *deny |= i ;
-       }
-}
-
-static int
-test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
-       unsigned int access, deny;
-
-       set_access(&access, stp->st_access_bmap);
-       set_deny(&deny, stp->st_deny_bmap);
-       if ((access & open->op_share_deny) || (deny & open->op_share_access))
-               return 0;
-       return 1;
-}
-
 /*
  * Called to check deny when READ with all zero stateid or
  * WRITE with all zero or all one stateid
@@ -2052,14 +2120,12 @@ out:
 }
 
 static inline void
-nfs4_file_downgrade(struct file *filp, unsigned int share_access)
+nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
 {
-       if (share_access & NFS4_SHARE_ACCESS_WRITE) {
-               drop_file_write_access(filp);
-               spin_lock(&filp->f_lock);
-               filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;
-               spin_unlock(&filp->f_lock);
-       }
+       if (share_access & NFS4_SHARE_ACCESS_WRITE)
+               nfs4_file_put_access(fp, O_WRONLY);
+       if (share_access & NFS4_SHARE_ACCESS_READ)
+               nfs4_file_put_access(fp, O_RDONLY);
 }
 
 /*
@@ -2255,6 +2321,13 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
        return NULL;
 }
 
+int share_access_to_flags(u32 share_access)
+{
+       share_access &= ~NFS4_SHARE_WANT_MASK;
+
+       return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
+}
+
 static __be32
 nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
                struct nfs4_delegation **dp)
@@ -2265,8 +2338,7 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
        *dp = find_delegation_file(fp, &open->op_delegate_stateid);
        if (*dp == NULL)
                goto out;
-       flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ?
-                                               RD_STATE : WR_STATE;
+       flags = share_access_to_flags(open->op_share_access);
        status = nfs4_check_delegmode(*dp, flags);
        if (status)
                *dp = NULL;
@@ -2308,30 +2380,53 @@ nfs4_alloc_stateid(void)
        return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
 }
 
+static inline int nfs4_access_to_access(u32 nfs4_access)
+{
+       int flags = 0;
+
+       if (nfs4_access & NFS4_SHARE_ACCESS_READ)
+               flags |= NFSD_MAY_READ;
+       if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
+               flags |= NFSD_MAY_WRITE;
+       return flags;
+}
+
+static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file
+*fp, struct svc_fh *cur_fh, u32 nfs4_access)
+{
+       __be32 status;
+       int oflag = nfs4_access_to_omode(nfs4_access);
+       int access = nfs4_access_to_access(nfs4_access);
+
+       if (!fp->fi_fds[oflag]) {
+               status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
+                       &fp->fi_fds[oflag]);
+               if (status == nfserr_dropit)
+                       status = nfserr_jukebox;
+               if (status)
+                       return status;
+       }
+       nfs4_file_get_access(fp, oflag);
+
+       return nfs_ok;
+}
+
 static __be32
 nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
-               struct nfs4_delegation *dp,
-               struct svc_fh *cur_fh, int flags)
+               struct nfs4_file *fp, struct svc_fh *cur_fh,
+               struct nfsd4_open *open)
 {
        struct nfs4_stateid *stp;
+       __be32 status;
 
        stp = nfs4_alloc_stateid();
        if (stp == NULL)
                return nfserr_resource;
 
-       if (dp) {
-               get_file(dp->dl_vfs_file);
-               stp->st_vfs_file = dp->dl_vfs_file;
-       } else {
-               __be32 status;
-               status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
-                               &stp->st_vfs_file);
-               if (status) {
-                       if (status == nfserr_dropit)
-                               status = nfserr_jukebox;
-                       kmem_cache_free(stateid_slab, stp);
-                       return status;
-               }
+       status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access);
+       if (status) {
+               kmem_cache_free(stateid_slab, stp);
+               return status;
        }
        *stpp = stp;
        return 0;
@@ -2353,35 +2448,30 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
 }
 
 static __be32
-nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
+nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
 {
-       struct file *filp = stp->st_vfs_file;
-       struct inode *inode = filp->f_path.dentry->d_inode;
-       unsigned int share_access, new_writer;
+       u32 op_share_access, new_access;
        __be32 status;
 
-       set_access(&share_access, stp->st_access_bmap);
-       new_writer = (~share_access) & open->op_share_access
-                       & NFS4_SHARE_ACCESS_WRITE;
-
-       if (new_writer) {
-               int err = get_write_access(inode);
-               if (err)
-                       return nfserrno(err);
-               err = mnt_want_write(cur_fh->fh_export->ex_path.mnt);
-               if (err)
-                       return nfserrno(err);
-               file_take_write(filp);
+       set_access(&new_access, stp->st_access_bmap);
+       new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK;
+
+       if (new_access) {
+               status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access);
+               if (status)
+                       return status;
        }
        status = nfsd4_truncate(rqstp, cur_fh, open);
        if (status) {
-               if (new_writer)
-                       put_write_access(inode);
+               if (new_access) {
+                       int oflag = nfs4_access_to_omode(new_access);
+                       nfs4_file_put_access(fp, oflag);
+               }
                return status;
        }
        /* remember the open */
-       filp->f_mode |= open->op_share_access;
-       __set_bit(open->op_share_access, &stp->st_access_bmap);
+       op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
+       __set_bit(op_share_access, &stp->st_access_bmap);
        __set_bit(open->op_share_deny, &stp->st_deny_bmap);
 
        return nfs_ok;
@@ -2444,13 +2534,14 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
        fl.fl_end = OFFSET_MAX;
        fl.fl_owner =  (fl_owner_t)dp;
-       fl.fl_file = stp->st_vfs_file;
+       fl.fl_file = find_readable_file(stp->st_file);
+       BUG_ON(!fl.fl_file);
        fl.fl_pid = current->tgid;
 
        /* vfs_setlease checks to see if delegation should be handed out.
         * the lock_manager callbacks fl_mylease and fl_change are used
         */
-       if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) {
+       if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) {
                dprintk("NFSD: setlease failed [%d], no delegation\n", status);
                unhash_delegation(dp);
                flag = NFS4_OPEN_DELEGATE_NONE;
@@ -2514,18 +2605,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
         */
        if (stp) {
                /* Stateid was found, this is an OPEN upgrade */
-               status = nfs4_upgrade_open(rqstp, current_fh, stp, open);
+               status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
                if (status)
                        goto out;
                update_stateid(&stp->st_stateid);
        } else {
-               /* Stateid was not found, this is a new OPEN */
-               int flags = 0;
-               if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
-                       flags |= NFSD_MAY_READ;
-               if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
-                       flags |= NFSD_MAY_WRITE;
-               status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);
+               status = nfs4_new_open(rqstp, &stp, fp, current_fh, open);
                if (status)
                        goto out;
                init_stateid(stp, fp, open);
@@ -2727,7 +2812,7 @@ search_close_lru(u32 st_id, int flags)
 static inline int
 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
 {
-       return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode;
+       return fhp->fh_dentry->d_inode != stp->st_file->fi_inode;
 }
 
 static int
@@ -2760,6 +2845,9 @@ __be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
 {
         __be32 status = nfserr_openmode;
 
+       /* For lock stateid's, we test the parent open, not the lock: */
+       if (stp->st_openstp)
+               stp = stp->st_openstp;
        if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
                 goto out;
        if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap)))
@@ -2872,7 +2960,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
                        goto out;
                renew_client(dp->dl_client);
                if (filpp)
-                       *filpp = dp->dl_vfs_file;
+                       *filpp = find_readable_file(dp->dl_file);
+               BUG_ON(!*filpp);
        } else { /* open or lock stateid */
                stp = find_stateid(stateid, flags);
                if (!stp)
@@ -2889,8 +2978,13 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
                if (status)
                        goto out;
                renew_client(stp->st_stateowner->so_client);
-               if (filpp)
-                       *filpp = stp->st_vfs_file;
+               if (filpp) {
+                       if (flags & RD_STATE)
+                               *filpp = find_readable_file(stp->st_file);
+                       else
+                               *filpp = find_writeable_file(stp->st_file);
+                       BUG_ON(!*filpp); /* assured by check_openmode */
+               }
        }
        status = nfs_ok;
 out:
@@ -3126,8 +3220,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
                goto out;
        }
        set_access(&share_access, stp->st_access_bmap);
-       nfs4_file_downgrade(stp->st_vfs_file,
-                           share_access & ~od->od_share_access);
+       nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access);
 
        reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);
        reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
@@ -3346,11 +3439,9 @@ static inline void
 nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
 {
        struct nfs4_stateowner *sop;
-       unsigned int hval;
 
        if (fl->fl_lmops == &nfsd_posix_mng_ops) {
                sop = (struct nfs4_stateowner *) fl->fl_owner;
-               hval = lockownerid_hashval(sop->so_id);
                kref_get(&sop->so_ref);
                deny->ld_sop = sop;
                deny->ld_clientid = sop->so_client->cl_clientid;
@@ -3446,8 +3537,6 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
        stp->st_stateid.si_stateownerid = sop->so_id;
        stp->st_stateid.si_fileid = fp->fi_id;
        stp->st_stateid.si_generation = 0;
-       stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
-       stp->st_access_bmap = open_stp->st_access_bmap;
        stp->st_deny_bmap = open_stp->st_deny_bmap;
        stp->st_openstp = open_stp;
 
@@ -3547,7 +3636,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                lock_sop = lock->lk_replay_owner;
        }
        /* lock->lk_replay_owner and lock_stp have been created or found */
-       filp = lock_stp->st_vfs_file;
 
        status = nfserr_grace;
        if (locks_in_grace() && !lock->lk_reclaim)
@@ -3560,11 +3648,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        switch (lock->lk_type) {
                case NFS4_READ_LT:
                case NFS4_READW_LT:
+                       filp = find_readable_file(lock_stp->st_file);
                        file_lock.fl_type = F_RDLCK;
                        cmd = F_SETLK;
                break;
                case NFS4_WRITE_LT:
                case NFS4_WRITEW_LT:
+                       filp = find_writeable_file(lock_stp->st_file);
                        file_lock.fl_type = F_WRLCK;
                        cmd = F_SETLK;
                break;
@@ -3572,6 +3662,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        status = nfserr_inval;
                goto out;
        }
+       if (!filp) {
+               status = nfserr_openmode;
+               goto out;
+       }
        file_lock.fl_owner = (fl_owner_t)lock_sop;
        file_lock.fl_pid = current->tgid;
        file_lock.fl_file = filp;
@@ -3740,7 +3834,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                                        &locku->lu_stateowner, &stp, NULL)))
                goto out;
 
-       filp = stp->st_vfs_file;
+       filp = find_any_file(stp->st_file);
+       if (!filp) {
+               status = nfserr_lock_range;
+               goto out;
+       }
        BUG_ON(!filp);
        locks_init_lock(&file_lock);
        file_lock.fl_type = F_UNLCK;
@@ -3787,10 +3885,10 @@ out_nfserr:
  *     0: no locks held by lockowner
  */
 static int
-check_for_locks(struct file *filp, struct nfs4_stateowner *lowner)
+check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner)
 {
        struct file_lock **flpp;
-       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct inode *inode = filp->fi_inode;
        int status = 0;
 
        lock_kernel();
@@ -3841,7 +3939,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
                                continue;
                        list_for_each_entry(stp, &sop->so_stateids,
                                        st_perstateowner) {
-                               if (check_for_locks(stp->st_vfs_file, sop))
+                               if (check_for_locks(stp->st_file, sop))
                                        goto out;
                                /* Note: so_perclient unused for lockowners,
                                 * so it's OK to fool with here. */
@@ -4066,16 +4164,8 @@ out_free_laundry:
 int
 nfs4_state_start(void)
 {
-       int ret;
-
-       if (nfs4_init)
-               return 0;
        nfsd4_load_reboot_recovery_data();
-       ret = __nfs4_state_start();
-       if (ret)
-               return ret;
-       nfs4_init = 1;
-       return 0;
+       return __nfs4_state_start();
 }
 
 static void
@@ -4110,7 +4200,6 @@ __nfs4_state_shutdown(void)
        }
 
        nfsd4_shutdown_recdir();
-       nfs4_init = 0;
 }
 
 void
index ac17a70802399b9a9766ad8f593a21266d60a7a1..f8931acb05f39586035e5bccfb906769d9334564 100644 (file)
@@ -2630,7 +2630,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
        }
        read->rd_vlen = v;
 
-       nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp,
+       nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp,
                        read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
                        &maxcount);
 
@@ -3325,6 +3325,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
                }
                /* Renew the clientid on success and on replay */
                release_session_client(cs->session);
+               nfsd4_put_session(cs->session);
        }
        return 1;
 }
index 508941c23af7fa425864eed3d3a173cd8a4a4474..b53b1d042f1ff3190b6696876da88cf355277b5a 100644 (file)
@@ -949,15 +949,12 @@ static ssize_t __write_ports_addfd(char *buf)
        if (err != 0)
                return err;
 
-       err = lockd_up();
-       if (err != 0)
-               goto out;
-
        err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
-       if (err < 0)
-               lockd_down();
+       if (err < 0) {
+               svc_destroy(nfsd_serv);
+               return err;
+       }
 
-out:
        /* Decrease the count, but don't shut down the service */
        nfsd_serv->sv_nrthreads--;
        return err;
@@ -978,9 +975,6 @@ static ssize_t __write_ports_delfd(char *buf)
        if (nfsd_serv != NULL)
                len = svc_sock_names(nfsd_serv, buf,
                                        SIMPLE_TRANSACTION_LIMIT, toclose);
-       if (len >= 0)
-               lockd_down();
-
        kfree(toclose);
        return len;
 }
@@ -1014,6 +1008,9 @@ static ssize_t __write_ports_addxprt(char *buf)
                                PF_INET6, port, SVC_SOCK_ANONYMOUS);
        if (err < 0 && err != -EAFNOSUPPORT)
                goto out_close;
+
+       /* Decrease the count, but don't shut down the service */
+       nfsd_serv->sv_nrthreads--;
        return 0;
 out_close:
        xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
@@ -1022,8 +1019,7 @@ out_close:
                svc_xprt_put(xprt);
        }
 out_err:
-       /* Decrease the count, but don't shut down the service */
-       nfsd_serv->sv_nrthreads--;
+       svc_destroy(nfsd_serv);
        return err;
 }
 
@@ -1194,7 +1190,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
                        bsize = NFSSVC_MAXBLKSIZE;
                bsize &= ~(1024-1);
                mutex_lock(&nfsd_mutex);
-               if (nfsd_serv && nfsd_serv->sv_nrthreads) {
+               if (nfsd_serv) {
                        mutex_unlock(&nfsd_mutex);
                        return -EBUSY;
                }
@@ -1310,6 +1306,8 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
                        return -EINVAL;
 
                status = nfs4_reset_recoverydir(recdir);
+               if (status)
+                       return status;
        }
 
        return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
index 72377761270ec581c333e77bd8c2263c8e3cc681..b76ac3a82e39f14438f2b3c5c886fe466b84a45d 100644 (file)
@@ -153,6 +153,7 @@ void                nfsd_lockd_shutdown(void);
 #define nfserr_bad_seqid       cpu_to_be32(NFSERR_BAD_SEQID)
 #define        nfserr_symlink          cpu_to_be32(NFSERR_SYMLINK)
 #define        nfserr_not_same         cpu_to_be32(NFSERR_NOT_SAME)
+#define nfserr_lock_range      cpu_to_be32(NFSERR_LOCK_RANGE)
 #define        nfserr_restorefh        cpu_to_be32(NFSERR_RESTOREFH)
 #define        nfserr_attrnotsupp      cpu_to_be32(NFSERR_ATTRNOTSUPP)
 #define        nfserr_bad_xdr          cpu_to_be32(NFSERR_BAD_XDR)
index a047ad6111ef2e1c6820097ee3b01a77de8ce20b..08e17264784b7f4dd2d5822cbb7c59a52a58f369 100644 (file)
@@ -144,7 +144,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
        svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
 
        resp->count = argp->count;
-       nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
+       nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
                                  argp->offset,
                                  rqstp->rq_vec, argp->vlen,
                                  &resp->count);
@@ -290,7 +290,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
         * gospel of sun micro
         */
        if (type != S_IFREG) {
-               int     is_borc = 0;
                if (type != S_IFBLK && type != S_IFCHR) {
                        rdev = 0;
                } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
@@ -298,7 +297,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
                        type = S_IFIFO;
                } else {
                        /* Okay, char or block special */
-                       is_borc = 1;
                        if (!rdev)
                                rdev = wanted;
                }
index 06b2a26edfe01736274e1d489988f73735f2913b..e2c43464f23764405fef5e525e3829777be1a1a7 100644 (file)
@@ -180,15 +180,80 @@ int nfsd_nrthreads(void)
        return rv;
 }
 
+static int nfsd_init_socks(int port)
+{
+       int error;
+       if (!list_empty(&nfsd_serv->sv_permsocks))
+               return 0;
+
+       error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
+                                       SVC_SOCK_DEFAULTS);
+       if (error < 0)
+               return error;
+
+       error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
+                                       SVC_SOCK_DEFAULTS);
+       if (error < 0)
+               return error;
+
+       return 0;
+}
+
+static bool nfsd_up = false;
+
+static int nfsd_startup(unsigned short port, int nrservs)
+{
+       int ret;
+
+       if (nfsd_up)
+               return 0;
+       /*
+        * Readahead param cache - will no-op if it already exists.
+        * (Note therefore results will be suboptimal if number of
+        * threads is modified after nfsd start.)
+        */
+       ret = nfsd_racache_init(2*nrservs);
+       if (ret)
+               return ret;
+       ret = nfsd_init_socks(port);
+       if (ret)
+               goto out_racache;
+       ret = lockd_up();
+       if (ret)
+               goto out_racache;
+       ret = nfs4_state_start();
+       if (ret)
+               goto out_lockd;
+       nfsd_up = true;
+       return 0;
+out_lockd:
+       lockd_down();
+out_racache:
+       nfsd_racache_shutdown();
+       return ret;
+}
+
+static void nfsd_shutdown(void)
+{
+       /*
+        * write_ports can create the server without actually starting
+        * any threads--if we get shut down before any threads are
+        * started, then nfsd_last_thread will be run before any of this
+        * other initialization has been done.
+        */
+       if (!nfsd_up)
+               return;
+       nfs4_state_shutdown();
+       lockd_down();
+       nfsd_racache_shutdown();
+       nfsd_up = false;
+}
+
 static void nfsd_last_thread(struct svc_serv *serv)
 {
        /* When last nfsd thread exits we need to do some clean-up */
-       struct svc_xprt *xprt;
-       list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list)
-               lockd_down();
        nfsd_serv = NULL;
-       nfsd_racache_shutdown();
-       nfs4_state_shutdown();
+       nfsd_shutdown();
 
        printk(KERN_WARNING "nfsd: last server has exited, flushing export "
                            "cache\n");
@@ -263,45 +328,18 @@ int nfsd_create_serv(void)
                       nfsd_max_blksize >= 8*1024*2)
                        nfsd_max_blksize /= 2;
        }
+       nfsd_reset_versions();
 
        nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
                                      nfsd_last_thread, nfsd, THIS_MODULE);
        if (nfsd_serv == NULL)
-               err = -ENOMEM;
-       else
-               set_max_drc();
+               return -ENOMEM;
 
+       set_max_drc();
        do_gettimeofday(&nfssvc_boot);          /* record boot time */
        return err;
 }
 
-static int nfsd_init_socks(int port)
-{
-       int error;
-       if (!list_empty(&nfsd_serv->sv_permsocks))
-               return 0;
-
-       error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
-                                       SVC_SOCK_DEFAULTS);
-       if (error < 0)
-               return error;
-
-       error = lockd_up();
-       if (error < 0)
-               return error;
-
-       error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
-                                       SVC_SOCK_DEFAULTS);
-       if (error < 0)
-               return error;
-
-       error = lockd_up();
-       if (error < 0)
-               return error;
-
-       return 0;
-}
-
 int nfsd_nrpools(void)
 {
        if (nfsd_serv == NULL)
@@ -376,10 +414,16 @@ int nfsd_set_nrthreads(int n, int *nthreads)
        return err;
 }
 
+/*
+ * Adjust the number of threads and return the new number of threads.
+ * This is also the function that starts the server if necessary, if
+ * this is the first time nrservs is nonzero.
+ */
 int
 nfsd_svc(unsigned short port, int nrservs)
 {
        int     error;
+       bool    nfsd_up_before;
 
        mutex_lock(&nfsd_mutex);
        dprintk("nfsd: creating service\n");
@@ -391,34 +435,29 @@ nfsd_svc(unsigned short port, int nrservs)
        if (nrservs == 0 && nfsd_serv == NULL)
                goto out;
 
-       /* Readahead param cache - will no-op if it already exists */
-       error = nfsd_racache_init(2*nrservs);
-       if (error<0)
-               goto out;
-       error = nfs4_state_start();
+       error = nfsd_create_serv();
        if (error)
                goto out;
 
-       nfsd_reset_versions();
-
-       error = nfsd_create_serv();
+       nfsd_up_before = nfsd_up;
 
+       error = nfsd_startup(port, nrservs);
        if (error)
-               goto out;
-       error = nfsd_init_socks(port);
-       if (error)
-               goto failure;
-
+               goto out_destroy;
        error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
-       if (error == 0)
-               /* We are holding a reference to nfsd_serv which
-                * we don't want to count in the return value,
-                * so subtract 1
-                */
-               error = nfsd_serv->sv_nrthreads - 1;
- failure:
+       if (error)
+               goto out_shutdown;
+       /* We are holding a reference to nfsd_serv which
+        * we don't want to count in the return value,
+        * so subtract 1
+        */
+       error = nfsd_serv->sv_nrthreads - 1;
+out_shutdown:
+       if (error < 0 && !nfsd_up_before)
+               nfsd_shutdown();
+out_destroy:
        svc_destroy(nfsd_serv);         /* Release server */
- out:
+out:
        mutex_unlock(&nfsd_mutex);
        return error;
 }
index 006c84230c7c5f71ab38d6f43e6a9329736a39eb..7731a75971ddf88347b7ed634604e72fcc0b027c 100644 (file)
@@ -88,7 +88,6 @@ struct nfs4_delegation {
        struct nfs4_client      *dl_client;
        struct nfs4_file        *dl_file;
        struct file_lock        *dl_flock;
-       struct file             *dl_vfs_file;
        u32                     dl_type;
        time_t                  dl_time;
 /* For recall: */
@@ -342,12 +341,50 @@ struct nfs4_file {
        struct list_head        fi_hash;    /* hash by "struct inode *" */
        struct list_head        fi_stateids;
        struct list_head        fi_delegations;
+       /* One each for O_RDONLY, O_WRONLY, O_RDWR: */
+       struct file *           fi_fds[3];
+       /* One each for O_RDONLY, O_WRONLY: */
+       atomic_t                fi_access[2];
+       /*
+        * Each open stateid contributes 1 to either fi_readers or
+        * fi_writers, or both, depending on the open mode.  A
+        * delegation also takes an fi_readers reference.  Lock
+        * stateid's take none.
+        */
+       atomic_t                fi_readers;
+       atomic_t                fi_writers;
        struct inode            *fi_inode;
        u32                     fi_id;      /* used with stateowner->so_id 
                                             * for stateid_hashtbl hash */
        bool                    fi_had_conflict;
 };
 
+/* XXX: for first cut may fall back on returning file that doesn't work
+ * at all? */
+static inline struct file *find_writeable_file(struct nfs4_file *f)
+{
+       if (f->fi_fds[O_RDWR])
+               return f->fi_fds[O_RDWR];
+       return f->fi_fds[O_WRONLY];
+}
+
+static inline struct file *find_readable_file(struct nfs4_file *f)
+{
+       if (f->fi_fds[O_RDWR])
+               return f->fi_fds[O_RDWR];
+       return f->fi_fds[O_RDONLY];
+}
+
+static inline struct file *find_any_file(struct nfs4_file *f)
+{
+       if (f->fi_fds[O_RDWR])
+               return f->fi_fds[O_RDWR];
+       else if (f->fi_fds[O_RDWR])
+               return f->fi_fds[O_WRONLY];
+       else
+               return f->fi_fds[O_RDONLY];
+}
+
 /*
 * nfs4_stateid can either be an open stateid or (eventually) a lock stateid
 *
@@ -373,7 +410,6 @@ struct nfs4_stateid {
        struct nfs4_stateowner      * st_stateowner;
        struct nfs4_file            * st_file;
        stateid_t                     st_stateid;
-       struct file                 * st_vfs_file;
        unsigned long                 st_access_bmap;
        unsigned long                 st_deny_bmap;
        struct nfs4_stateid         * st_openstp;
index 3c111120b619ff20c7b74a81e081801d4965b08e..9df85a13af28b03fadc9fa47ae61aeffb4dc911c 100644 (file)
@@ -604,7 +604,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac
        return error;
 }
 
-#endif /* defined(CONFIG_NFS_V4) */
+#endif /* defined(CONFIG_NFSD_V4) */
 
 #ifdef CONFIG_NFSD_V3
 /*
@@ -903,7 +903,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
               loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
 {
        struct inode *inode;
-       struct raparms  *ra;
        mm_segment_t    oldfs;
        __be32          err;
        int             host_err;
@@ -914,12 +913,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))
                goto out;
 
-       /* Get readahead parameters */
-       ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
-
-       if (ra && ra->p_set)
-               file->f_ra = ra->p_ra;
-
        if (file->f_op->splice_read && rqstp->rq_splice_ok) {
                struct splice_desc sd = {
                        .len            = 0,
@@ -937,16 +930,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
                set_fs(oldfs);
        }
 
-       /* Write back readahead params */
-       if (ra) {
-               struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
-               spin_lock(&rab->pb_lock);
-               ra->p_ra = file->f_ra;
-               ra->p_set = 1;
-               ra->p_count--;
-               spin_unlock(&rab->pb_lock);
-       }
-
        if (host_err >= 0) {
                nfsdstats.io_read += host_err;
                *count = host_err;
@@ -1086,8 +1069,45 @@ out:
  * on entry. On return, *count contains the number of bytes actually read.
  * N.B. After this call fhp needs an fh_put
  */
+__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+       loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
+{
+       struct file *file;
+       struct inode *inode;
+       struct raparms  *ra;
+       __be32 err;
+
+       err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
+       if (err)
+               return err;
+
+       inode = file->f_path.dentry->d_inode;
+
+       /* Get readahead parameters */
+       ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
+
+       if (ra && ra->p_set)
+               file->f_ra = ra->p_ra;
+
+       err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
+
+       /* Write back readahead params */
+       if (ra) {
+               struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
+               spin_lock(&rab->pb_lock);
+               ra->p_ra = file->f_ra;
+               ra->p_set = 1;
+               ra->p_count--;
+               spin_unlock(&rab->pb_lock);
+       }
+
+       nfsd_close(file);
+       return err;
+}
+
+/* As above, but use the provided file descriptor. */
 __be32
-nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+nfsd_read_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
                loff_t offset, struct kvec *vec, int vlen,
                unsigned long *count)
 {
@@ -1099,13 +1119,8 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
                if (err)
                        goto out;
                err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
-       } else {
-               err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
-               if (err)
-                       goto out;
-               err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
-               nfsd_close(file);
-       }
+       } else /* Note file may still be NULL in NFSv4 special stateid case: */
+               err = nfsd_read(rqstp, fhp, offset, vec, vlen, count);
 out:
        return err;
 }
@@ -1631,7 +1646,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
                                char *name, int len, struct svc_fh *tfhp)
 {
        struct dentry   *ddir, *dnew, *dold;
-       struct inode    *dirp, *dest;
+       struct inode    *dirp;
        __be32          err;
        int             host_err;
 
@@ -1659,7 +1674,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
                goto out_nfserr;
 
        dold = tfhp->fh_dentry;
-       dest = dold->d_inode;
 
        host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt);
        if (host_err) {
@@ -2038,7 +2052,6 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
                                        struct dentry *dentry, int acc)
 {
        struct inode    *inode = dentry->d_inode;
-       struct path     path;
        int             err;
 
        if (acc == NFSD_MAY_NOP)
@@ -2111,15 +2124,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
        if (err == -EACCES && S_ISREG(inode->i_mode) &&
            acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE))
                err = inode_permission(inode, MAY_EXEC);
-       if (err)
-               goto nfsd_out;
 
-       /* Do integrity (permission) checking now, but defer incrementing
-        * IMA counts to the actual file open.
-        */
-       path.mnt = exp->ex_path.mnt;
-       path.dentry = dentry;
-nfsd_out:
        return err? nfserrno(err) : 0;
 }
 
index 217a62c2a3576ec7bb47e8ca3b8332de4ff1ad93..9a370a5e36b7ea9409b0b5b250ff88b6d5bee6ce 100644 (file)
@@ -64,7 +64,9 @@ __be32                nfsd_commit(struct svc_rqst *, struct svc_fh *,
 __be32         nfsd_open(struct svc_rqst *, struct svc_fh *, int,
                                int, struct file **);
 void           nfsd_close(struct file *);
-__be32                 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
+__be32                 nfsd_read(struct svc_rqst *, struct svc_fh *,
+                               loff_t, struct kvec *, int, unsigned long *);
+__be32                 nfsd_read_file(struct svc_rqst *, struct svc_fh *, struct file *,
                                loff_t, struct kvec *, int, unsigned long *);
 __be32                 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
                                loff_t, struct kvec *,int, unsigned long *, int *);
index 6f52b4d7c447dbfebe4c19ef6584edf331f3199b..7bf3e84b92f43c1e331040b735bf3faff67fd697 100644 (file)
@@ -192,6 +192,7 @@ extern int cache_check(struct cache_detail *detail,
 extern void cache_flush(void);
 extern void cache_purge(struct cache_detail *detail);
 #define NEVER (0x7FFFFFFF)
+extern void __init cache_initialize(void);
 extern int cache_register(struct cache_detail *cd);
 extern void cache_unregister(struct cache_detail *cd);
 
index 58de76c8540c65dac38999ea4c9a5c2af5303f92..2b06410e584e10d3f557b3b4bb58d0c660f56283 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/sunrpc/cache.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
-#include <linux/smp_lock.h>
 
 #define         RPCDBG_FACILITY RPCDBG_CACHE
 
@@ -320,7 +319,7 @@ static struct cache_detail *current_detail;
 static int current_index;
 
 static void do_cache_clean(struct work_struct *work);
-static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean);
+static struct delayed_work cache_cleaner;
 
 static void sunrpc_init_cache_detail(struct cache_detail *cd)
 {
@@ -1504,6 +1503,11 @@ static int create_cache_proc_entries(struct cache_detail *cd)
 }
 #endif
 
+void __init cache_initialize(void)
+{
+       INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean);
+}
+
 int cache_register(struct cache_detail *cd)
 {
        int ret;
index 34b58f9e704ad6c3656e10c941f04dd4f4025ec1..c0d085013a2be26f7bf3f34e195cebfc0a716039 100644 (file)
@@ -44,6 +44,7 @@ init_sunrpc(void)
 #ifdef CONFIG_PROC_FS
        rpc_proc_init();
 #endif
+       cache_initialize();
        cache_register(&ip_map_cache);
        cache_register(&unix_gid_cache);
        svc_init_xprt_sock();   /* svc sock transport */