Merge branch 'for-3.11' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Jul 2013 20:43:55 +0000 (13:43 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Jul 2013 20:43:55 +0000 (13:43 -0700)
Pull nfsd bugfixes from Bruce Fields:
 "Just three minor bugfixes"

* 'for-3.11' of git://linux-nfs.org/~bfields/linux:
  svcrdma: underflow issue in decode_write_list()
  nfsd4: fix minorversion support interface
  lockd: protect nlm_blocked access in nlmsvc_retry_blocked

fs/lockd/svclock.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfsd.h
fs/nfsd/nfssvc.c
net/sunrpc/xprtrdma/svc_rdma_marshal.c

index 067778b0ccc9dddd878277d6ca88e9c5d2fddc5b..e066a3902973640ae3d75dc0c768ceb8f15eb9d8 100644 (file)
@@ -951,6 +951,7 @@ nlmsvc_retry_blocked(void)
        unsigned long   timeout = MAX_SCHEDULE_TIMEOUT;
        struct nlm_block *block;
 
+       spin_lock(&nlm_blocked_lock);
        while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
                block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
 
@@ -960,6 +961,7 @@ nlmsvc_retry_blocked(void)
                        timeout = block->b_when - jiffies;
                        break;
                }
+               spin_unlock(&nlm_blocked_lock);
 
                dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
                        block, block->b_when);
@@ -969,7 +971,9 @@ nlmsvc_retry_blocked(void)
                        retry_deferred_block(block);
                } else
                        nlmsvc_grant_blocked(block);
+               spin_lock(&nlm_blocked_lock);
        }
+       spin_unlock(&nlm_blocked_lock);
 
        return timeout;
 }
index a7cee864e7b245e5ead7c8f04b509a5cfe9c59a8..0d4c410e45893c2ae00064c5a8ae3384e00848b4 100644 (file)
@@ -1293,7 +1293,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
         * According to RFC3010, this takes precedence over all other errors.
         */
        status = nfserr_minor_vers_mismatch;
-       if (args->minorversion > nfsd_supported_minorversion)
+       if (nfsd_minorversion(args->minorversion, NFSD_TEST) <= 0)
                goto out;
 
        status = nfs41_check_op_ordering(args);
index 2bbd94e51efc7dcc8bcba377e2e8373290b3a189..30f34ab02137f8e41aa95bcbf7c51967e694f3c1 100644 (file)
@@ -53,7 +53,6 @@ struct readdir_cd {
 extern struct svc_program      nfsd_program;
 extern struct svc_version      nfsd_version2, nfsd_version3,
                                nfsd_version4;
-extern u32                     nfsd_supported_minorversion;
 extern struct mutex            nfsd_mutex;
 extern spinlock_t              nfsd_drc_lock;
 extern unsigned long           nfsd_drc_max_mem;
index 6b9f48ca4c25183abab7759a588a8ec5d4da4257..760c85a6f534a45b0eb396a62acc305484163109 100644 (file)
@@ -116,7 +116,10 @@ struct svc_program         nfsd_program = {
 
 };
 
-u32 nfsd_supported_minorversion = 1;
+static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = {
+       [0] = 1,
+       [1] = 1,
+};
 
 int nfsd_vers(int vers, enum vers_op change)
 {
@@ -151,15 +154,13 @@ int nfsd_minorversion(u32 minorversion, enum vers_op change)
                return -1;
        switch(change) {
        case NFSD_SET:
-               nfsd_supported_minorversion = minorversion;
+               nfsd_supported_minorversions[minorversion] = true;
                break;
        case NFSD_CLEAR:
-               if (minorversion == 0)
-                       return -1;
-               nfsd_supported_minorversion = minorversion - 1;
+               nfsd_supported_minorversions[minorversion] = false;
                break;
        case NFSD_TEST:
-               return minorversion <= nfsd_supported_minorversion;
+               return nfsd_supported_minorversions[minorversion];
        case NFSD_AVAIL:
                return minorversion <= NFSD_SUPPORTED_MINOR_VERSION;
        }
index 8d2edddf48cf13c6d283bd8784e61c7601f23fc7..65b146297f5acfa8f5ab08e4d6f1ae0df865b4f6 100644 (file)
@@ -98,6 +98,7 @@ void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch,
  */
 static u32 *decode_write_list(u32 *va, u32 *vaend)
 {
+       unsigned long start, end;
        int nchunks;
 
        struct rpcrdma_write_array *ary =
@@ -113,9 +114,12 @@ static u32 *decode_write_list(u32 *va, u32 *vaend)
                return NULL;
        }
        nchunks = ntohl(ary->wc_nchunks);
-       if (((unsigned long)&ary->wc_array[0] +
-            (sizeof(struct rpcrdma_write_chunk) * nchunks)) >
-           (unsigned long)vaend) {
+
+       start = (unsigned long)&ary->wc_array[0];
+       end = (unsigned long)vaend;
+       if (nchunks < 0 ||
+           nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
+           (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
                dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
                        ary, nchunks, vaend);
                return NULL;
@@ -129,6 +133,7 @@ static u32 *decode_write_list(u32 *va, u32 *vaend)
 
 static u32 *decode_reply_array(u32 *va, u32 *vaend)
 {
+       unsigned long start, end;
        int nchunks;
        struct rpcrdma_write_array *ary =
                (struct rpcrdma_write_array *)va;
@@ -143,9 +148,12 @@ static u32 *decode_reply_array(u32 *va, u32 *vaend)
                return NULL;
        }
        nchunks = ntohl(ary->wc_nchunks);
-       if (((unsigned long)&ary->wc_array[0] +
-            (sizeof(struct rpcrdma_write_chunk) * nchunks)) >
-           (unsigned long)vaend) {
+
+       start = (unsigned long)&ary->wc_array[0];
+       end = (unsigned long)vaend;
+       if (nchunks < 0 ||
+           nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
+           (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
                dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
                        ary, nchunks, vaend);
                return NULL;