NFSD: Fix nfs4_verifier memory alignment
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / nfsd / nfs4state.c
index ffb46d6..e318964 100644 (file)
@@ -95,6 +95,19 @@ nfs4_lock_state(void)
        mutex_lock(&client_mutex);
 }
 
+static void free_session(struct kref *);
+
+/* Must be called under the client_lock */
+static void nfsd4_put_session_locked(struct nfsd4_session *ses)
+{
+       kref_put(&ses->se_ref, free_session);
+}
+
+static void nfsd4_get_session(struct nfsd4_session *ses)
+{
+       kref_get(&ses->se_ref);
+}
+
 void
 nfs4_unlock_state(void)
 {
@@ -609,12 +622,20 @@ hash_sessionid(struct nfs4_sessionid *sessionid)
        return sid->sequence % SESSION_HASH_SIZE;
 }
 
+#ifdef NFSD_DEBUG
 static inline void
 dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
 {
        u32 *ptr = (u32 *)(&sessionid->data[0]);
        dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
 }
+#else
+static inline void
+dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
+{
+}
+#endif
+
 
 static void
 gen_sessionid(struct nfsd4_session *ses)
@@ -836,11 +857,12 @@ static void nfsd4_del_conns(struct nfsd4_session *s)
        spin_unlock(&clp->cl_lock);
 }
 
-void free_session(struct kref *kref)
+static void free_session(struct kref *kref)
 {
        struct nfsd4_session *ses;
        int mem;
 
+       BUG_ON(!spin_is_locked(&client_lock));
        ses = container_of(kref, struct nfsd4_session, se_ref);
        nfsd4_del_conns(ses);
        spin_lock(&nfsd_drc_lock);
@@ -851,6 +873,13 @@ void free_session(struct kref *kref)
        kfree(ses);
 }
 
+void nfsd4_put_session(struct nfsd4_session *ses)
+{
+       spin_lock(&client_lock);
+       nfsd4_put_session_locked(ses);
+       spin_unlock(&client_lock);
+}
+
 static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
 {
        struct nfsd4_session *new;
@@ -898,7 +927,9 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
        status = nfsd4_new_conn_from_crses(rqstp, new);
        /* whoops: benny points out, status is ignored! (err, or bogus) */
        if (status) {
+               spin_lock(&client_lock);
                free_session(&new->se_ref);
+               spin_unlock(&client_lock);
                return NULL;
        }
        if (cses->flags & SESSION4_BACK_CHAN) {
@@ -1010,12 +1041,13 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
 static inline void
 free_client(struct nfs4_client *clp)
 {
+       BUG_ON(!spin_is_locked(&client_lock));
        while (!list_empty(&clp->cl_sessions)) {
                struct nfsd4_session *ses;
                ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
                                se_perclnt);
                list_del(&ses->se_perclnt);
-               nfsd4_put_session(ses);
+               nfsd4_put_session_locked(ses);
        }
        if (clp->cl_cred.cr_group_info)
                put_group_info(clp->cl_cred.cr_group_info);
@@ -1142,12 +1174,12 @@ static void gen_clid(struct nfs4_client *clp)
 
 static void gen_confirm(struct nfs4_client *clp)
 {
+       __be32 verf[2];
        static u32 i;
-       u32 *p;
 
-       p = (u32 *)clp->cl_confirm.data;
-       *p++ = get_seconds();
-       *p++ = i++;
+       verf[0] = (__be32)get_seconds();
+       verf[1] = (__be32)i++;
+       memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
 }
 
 static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
@@ -1184,7 +1216,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
        if (princ) {
                clp->cl_principal = kstrdup(princ, GFP_KERNEL);
                if (clp->cl_principal == NULL) {
+                       spin_lock(&client_lock);
                        free_client(clp);
+                       spin_unlock(&client_lock);
                        return NULL;
                }
        }
@@ -1812,9 +1846,10 @@ nfsd4_destroy_session(struct svc_rqst *r,
        nfsd4_probe_callback_sync(ses->se_client);
        nfs4_unlock_state();
 
+       spin_lock(&client_lock);
        nfsd4_del_conns(ses);
-
-       nfsd4_put_session(ses);
+       nfsd4_put_session_locked(ses);
+       spin_unlock(&client_lock);
        status = nfs_ok;
 out:
        dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -2862,6 +2897,27 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
        return 0;
 }
 
+static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
+{
+       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+       if (status == -EAGAIN)
+               open->op_why_no_deleg = WND4_CONTENTION;
+       else {
+               open->op_why_no_deleg = WND4_RESOURCE;
+               switch (open->op_deleg_want) {
+               case NFS4_SHARE_WANT_READ_DELEG:
+               case NFS4_SHARE_WANT_WRITE_DELEG:
+               case NFS4_SHARE_WANT_ANY_DELEG:
+                       break;
+               case NFS4_SHARE_WANT_CANCEL:
+                       open->op_why_no_deleg = WND4_CANCELLED;
+                       break;
+               case NFS4_SHARE_WANT_NO_DELEG:
+                       BUG();  /* not supposed to get here */
+               }
+       }
+}
+
 /*
  * Attempt to hand out a delegation.
  */
@@ -2918,25 +2974,9 @@ out:
                    open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
                        dprintk("NFSD: WARNING: refusing delegation reclaim\n");
 
-               if (open->op_deleg_want) {
-                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
-                       if (status == -EAGAIN)
-                               open->op_why_no_deleg = WND4_CONTENTION;
-                       else {
-                               open->op_why_no_deleg = WND4_RESOURCE;
-                               switch (open->op_deleg_want) {
-                               case NFS4_SHARE_WANT_READ_DELEG:
-                               case NFS4_SHARE_WANT_WRITE_DELEG:
-                               case NFS4_SHARE_WANT_ANY_DELEG:
-                                       break;
-                               case NFS4_SHARE_WANT_CANCEL:
-                                       open->op_why_no_deleg = WND4_CANCELLED;
-                                       break;
-                               case NFS4_SHARE_WANT_NO_DELEG:
-                                       BUG();  /* not supposed to get here */
-                               }
-                       }
-               }
+               /* 4.1 client asking for a delegation? */
+               if (open->op_deleg_want)
+                       nfsd4_open_deleg_none_ext(open, status);
        }
        return;
 out_free:
@@ -2946,6 +2986,24 @@ out_no_deleg:
        goto out;
 }
 
+static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
+                                       struct nfs4_delegation *dp)
+{
+       if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
+           dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
+               open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+               open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
+       } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
+                  dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
+               open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+               open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
+       }
+       /* Otherwise the client must be confused wanting a delegation
+        * it already has, therefore we don't return
+        * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
+        */
+}
+
 /*
  * called with nfs4_lock_state() held.
  */
@@ -3030,21 +3088,8 @@ nodeleg:
 out:
        /* 4.1 client trying to upgrade/downgrade delegation? */
        if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
-           open->op_deleg_want) {
-               if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
-                   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
-                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
-                       open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
-               } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
-                          dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
-                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
-                       open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
-               }
-               /* Otherwise the client must be confused wanting a delegation
-                * it already has, therefore we don't return
-                * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
-                */
-       }
+           open->op_deleg_want)
+               nfsd4_deleg_xgrade_none_ext(open, dp);
 
        if (fp)
                put_nfs4_file(fp);
@@ -4706,6 +4751,7 @@ nfs4_state_start(void)
 out_free_laundry:
        destroy_workqueue(laundry_wq);
 out_recovery:
+       nfs4_release_reclaim();
        nfsd4_shutdown_recdir();
        return ret;
 }