]> Pileus Git - ~andy/linux/commitdiff
Merge nfs containerization work from Trond's tree
authorJ. Bruce Fields <bfields@redhat.com>
Wed, 21 Mar 2012 20:42:14 +0000 (16:42 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Mon, 26 Mar 2012 15:48:54 +0000 (11:48 -0400)
The nfs containerization work is a prerequisite for Jeff Layton's reboot
recovery rework.

27 files changed:
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/hash.c
fs/lockd/svc.c
fs/nfsd/current_stateid.h [new file with mode: 0644]
fs/nfsd/export.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfssvc.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/nfsd/xdr4.h
include/linux/fs.h
include/linux/nfs4.h
include/linux/sunrpc/svc_rdma.h
net/sunrpc/cache.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/sunrpc/xprtrdma/svc_rdma.c
net/sunrpc/xprtrdma/svc_rdma_marshal.c
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/xprt_rdma.h

index 164c56092e5865a99238893c5717efc60a7aea4e..689d1b1a3f457ebde95ca5591a0081f66418d3c2 100644 (file)
@@ -32,24 +32,8 @@ static unsigned char ext4_filetype_table[] = {
        DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
 
-static int ext4_readdir(struct file *, void *, filldir_t);
 static int ext4_dx_readdir(struct file *filp,
                           void *dirent, filldir_t filldir);
-static int ext4_release_dir(struct inode *inode,
-                               struct file *filp);
-
-const struct file_operations ext4_dir_operations = {
-       .llseek         = ext4_llseek,
-       .read           = generic_read_dir,
-       .readdir        = ext4_readdir,         /* we take BKL. needed?*/
-       .unlocked_ioctl = ext4_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = ext4_compat_ioctl,
-#endif
-       .fsync          = ext4_sync_file,
-       .release        = ext4_release_dir,
-};
-
 
 static unsigned char get_dtype(struct super_block *sb, int filetype)
 {
@@ -60,6 +44,26 @@ static unsigned char get_dtype(struct super_block *sb, int filetype)
        return (ext4_filetype_table[filetype]);
 }
 
+/**
+ * Check if the given dir-inode refers to an htree-indexed directory
+ * (or a directory which chould potentially get coverted to use htree
+ * indexing).
+ *
+ * Return 1 if it is a dx dir, 0 if not
+ */
+static int is_dx_dir(struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+
+       if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
+                    EXT4_FEATURE_COMPAT_DIR_INDEX) &&
+           ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
+            ((inode->i_size >> sb->s_blocksize_bits) == 1)))
+               return 1;
+
+       return 0;
+}
+
 /*
  * Return 0 if the directory entry is OK, and 1 if there is a problem
  *
@@ -115,18 +119,13 @@ static int ext4_readdir(struct file *filp,
        unsigned int offset;
        int i, stored;
        struct ext4_dir_entry_2 *de;
-       struct super_block *sb;
        int err;
        struct inode *inode = filp->f_path.dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
        int ret = 0;
        int dir_has_error = 0;
 
-       sb = inode->i_sb;
-
-       if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
-                                   EXT4_FEATURE_COMPAT_DIR_INDEX) &&
-           ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
-            ((inode->i_size >> sb->s_blocksize_bits) == 1))) {
+       if (is_dx_dir(inode)) {
                err = ext4_dx_readdir(filp, dirent, filldir);
                if (err != ERR_BAD_DX_DIR) {
                        ret = err;
@@ -254,22 +253,134 @@ out:
        return ret;
 }
 
+static inline int is_32bit_api(void)
+{
+#ifdef CONFIG_COMPAT
+       return is_compat_task();
+#else
+       return (BITS_PER_LONG == 32);
+#endif
+}
+
 /*
  * These functions convert from the major/minor hash to an f_pos
- * value.
+ * value for dx directories
+ *
+ * Upper layer (for example NFS) should specify FMODE_32BITHASH or
+ * FMODE_64BITHASH explicitly. On the other hand, we allow ext4 to be mounted
+ * directly on both 32-bit and 64-bit nodes, under such case, neither
+ * FMODE_32BITHASH nor FMODE_64BITHASH is specified.
+ */
+static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
+{
+       if ((filp->f_mode & FMODE_32BITHASH) ||
+           (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
+               return major >> 1;
+       else
+               return ((__u64)(major >> 1) << 32) | (__u64)minor;
+}
+
+static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
+{
+       if ((filp->f_mode & FMODE_32BITHASH) ||
+           (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
+               return (pos << 1) & 0xffffffff;
+       else
+               return ((pos >> 32) << 1) & 0xffffffff;
+}
+
+static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
+{
+       if ((filp->f_mode & FMODE_32BITHASH) ||
+           (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
+               return 0;
+       else
+               return pos & 0xffffffff;
+}
+
+/*
+ * Return 32- or 64-bit end-of-file for dx directories
+ */
+static inline loff_t ext4_get_htree_eof(struct file *filp)
+{
+       if ((filp->f_mode & FMODE_32BITHASH) ||
+           (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
+               return EXT4_HTREE_EOF_32BIT;
+       else
+               return EXT4_HTREE_EOF_64BIT;
+}
+
+
+/*
+ * ext4_dir_llseek() based on generic_file_llseek() to handle both
+ * non-htree and htree directories, where the "offset" is in terms
+ * of the filename hash value instead of the byte offset.
  *
- * Currently we only use major hash numer.  This is unfortunate, but
- * on 32-bit machines, the same VFS interface is used for lseek and
- * llseek, so if we use the 64 bit offset, then the 32-bit versions of
- * lseek/telldir/seekdir will blow out spectacularly, and from within
- * the ext2 low-level routine, we don't know if we're being called by
- * a 64-bit version of the system call or the 32-bit version of the
- * system call.  Worse yet, NFSv2 only allows for a 32-bit readdir
- * cookie.  Sigh.
+ * NOTE: offsets obtained *before* ext4_set_inode_flag(dir, EXT4_INODE_INDEX)
+ *       will be invalid once the directory was converted into a dx directory
  */
-#define hash2pos(major, minor) (major >> 1)
-#define pos2maj_hash(pos)      ((pos << 1) & 0xffffffff)
-#define pos2min_hash(pos)      (0)
+loff_t ext4_dir_llseek(struct file *file, loff_t offset, int origin)
+{
+       struct inode *inode = file->f_mapping->host;
+       loff_t ret = -EINVAL;
+       int dx_dir = is_dx_dir(inode);
+
+       mutex_lock(&inode->i_mutex);
+
+       /* NOTE: relative offsets with dx directories might not work
+        *       as expected, as it is difficult to figure out the
+        *       correct offset between dx hashes */
+
+       switch (origin) {
+       case SEEK_END:
+               if (unlikely(offset > 0))
+                       goto out_err; /* not supported for directories */
+
+               /* so only negative offsets are left, does that have a
+                * meaning for directories at all? */
+               if (dx_dir)
+                       offset += ext4_get_htree_eof(file);
+               else
+                       offset += inode->i_size;
+               break;
+       case SEEK_CUR:
+               /*
+                * Here we special-case the lseek(fd, 0, SEEK_CUR)
+                * position-querying operation.  Avoid rewriting the "same"
+                * f_pos value back to the file because a concurrent read(),
+                * write() or lseek() might have altered it
+                */
+               if (offset == 0) {
+                       offset = file->f_pos;
+                       goto out_ok;
+               }
+
+               offset += file->f_pos;
+               break;
+       }
+
+       if (unlikely(offset < 0))
+               goto out_err;
+
+       if (!dx_dir) {
+               if (offset > inode->i_sb->s_maxbytes)
+                       goto out_err;
+       } else if (offset > ext4_get_htree_eof(file))
+               goto out_err;
+
+       /* Special lock needed here? */
+       if (offset != file->f_pos) {
+               file->f_pos = offset;
+               file->f_version = 0;
+       }
+
+out_ok:
+       ret = offset;
+out_err:
+       mutex_unlock(&inode->i_mutex);
+
+       return ret;
+}
 
 /*
  * This structure holds the nodes of the red-black tree used to store
@@ -330,15 +441,16 @@ static void free_rb_tree_fname(struct rb_root *root)
 }
 
 
-static struct dir_private_info *ext4_htree_create_dir_info(loff_t pos)
+static struct dir_private_info *ext4_htree_create_dir_info(struct file *filp,
+                                                          loff_t pos)
 {
        struct dir_private_info *p;
 
        p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL);
        if (!p)
                return NULL;
-       p->curr_hash = pos2maj_hash(pos);
-       p->curr_minor_hash = pos2min_hash(pos);
+       p->curr_hash = pos2maj_hash(filp, pos);
+       p->curr_minor_hash = pos2min_hash(filp, pos);
        return p;
 }
 
@@ -429,7 +541,7 @@ static int call_filldir(struct file *filp, void *dirent,
                       "null fname?!?\n");
                return 0;
        }
-       curr_pos = hash2pos(fname->hash, fname->minor_hash);
+       curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
        while (fname) {
                error = filldir(dirent, fname->name,
                                fname->name_len, curr_pos,
@@ -454,13 +566,13 @@ static int ext4_dx_readdir(struct file *filp,
        int     ret;
 
        if (!info) {
-               info = ext4_htree_create_dir_info(filp->f_pos);
+               info = ext4_htree_create_dir_info(filp, filp->f_pos);
                if (!info)
                        return -ENOMEM;
                filp->private_data = info;
        }
 
-       if (filp->f_pos == EXT4_HTREE_EOF)
+       if (filp->f_pos == ext4_get_htree_eof(filp))
                return 0;       /* EOF */
 
        /* Some one has messed with f_pos; reset the world */
@@ -468,8 +580,8 @@ static int ext4_dx_readdir(struct file *filp,
                free_rb_tree_fname(&info->root);
                info->curr_node = NULL;
                info->extra_fname = NULL;
-               info->curr_hash = pos2maj_hash(filp->f_pos);
-               info->curr_minor_hash = pos2min_hash(filp->f_pos);
+               info->curr_hash = pos2maj_hash(filp, filp->f_pos);
+               info->curr_minor_hash = pos2min_hash(filp, filp->f_pos);
        }
 
        /*
@@ -501,7 +613,7 @@ static int ext4_dx_readdir(struct file *filp,
                        if (ret < 0)
                                return ret;
                        if (ret == 0) {
-                               filp->f_pos = EXT4_HTREE_EOF;
+                               filp->f_pos = ext4_get_htree_eof(filp);
                                break;
                        }
                        info->curr_node = rb_first(&info->root);
@@ -521,7 +633,7 @@ static int ext4_dx_readdir(struct file *filp,
                        info->curr_minor_hash = fname->minor_hash;
                } else {
                        if (info->next_hash == ~0) {
-                               filp->f_pos = EXT4_HTREE_EOF;
+                               filp->f_pos = ext4_get_htree_eof(filp);
                                break;
                        }
                        info->curr_hash = info->next_hash;
@@ -540,3 +652,15 @@ static int ext4_release_dir(struct inode *inode, struct file *filp)
 
        return 0;
 }
+
+const struct file_operations ext4_dir_operations = {
+       .llseek         = ext4_dir_llseek,
+       .read           = generic_read_dir,
+       .readdir        = ext4_readdir,
+       .unlocked_ioctl = ext4_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = ext4_compat_ioctl,
+#endif
+       .fsync          = ext4_sync_file,
+       .release        = ext4_release_dir,
+};
index 513004fc3d840ee03586a4fedcdb133d8031c642..8b64a00502a0fee29921534175dd42a68d5adad7 100644 (file)
@@ -1612,7 +1612,11 @@ struct dx_hash_info
        u32             *seed;
 };
 
-#define EXT4_HTREE_EOF 0x7fffffff
+
+/* 32 and 64 bit signed EOF for dx directories */
+#define EXT4_HTREE_EOF_32BIT   ((1UL  << (32 - 1)) - 1)
+#define EXT4_HTREE_EOF_64BIT   ((1ULL << (64 - 1)) - 1)
+
 
 /*
  * Control parameters used by ext4_htree_next_block
index ac8f168c8ab435fcd868854cfdbc4d5d0787c6ad..fa8e4911d3545cdc78b1142cf74026785daa0840 100644 (file)
@@ -200,8 +200,8 @@ int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo)
                return -1;
        }
        hash = hash & ~1;
-       if (hash == (EXT4_HTREE_EOF << 1))
-               hash = (EXT4_HTREE_EOF-1) << 1;
+       if (hash == (EXT4_HTREE_EOF_32BIT << 1))
+               hash = (EXT4_HTREE_EOF_32BIT - 1) << 1;
        hinfo->hash = hash;
        hinfo->minor_hash = minor_hash;
        return 0;
index 2774e1013b34467acc3c1c6bc55f47fcac8d3ca7..f49b9afc443690a2377db100ed7da33452ef98db 100644 (file)
@@ -496,7 +496,7 @@ static int param_set_##name(const char *val, struct kernel_param *kp)       \
        __typeof__(type) num = which_strtol(val, &endp, 0);             \
        if (endp == val || *endp || num < (min) || num > (max))         \
                return -EINVAL;                                         \
-       *((int *) kp->arg) = num;                                       \
+       *((type *) kp->arg) = num;                                      \
        return 0;                                                       \
 }
 
diff --git a/fs/nfsd/current_stateid.h b/fs/nfsd/current_stateid.h
new file mode 100644 (file)
index 0000000..4123551
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _NFSD4_CURRENT_STATE_H
+#define _NFSD4_CURRENT_STATE_H
+
+#include "state.h"
+#include "xdr4.h"
+
+extern void clear_current_stateid(struct nfsd4_compound_state *cstate);
+/*
+ * functions to set current state id
+ */
+extern void nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *);
+extern void nfsd4_set_openstateid(struct nfsd4_compound_state *, struct nfsd4_open *);
+extern void nfsd4_set_lockstateid(struct nfsd4_compound_state *, struct nfsd4_lock *);
+extern void nfsd4_set_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *);
+
+/*
+ * functions to consume current state id
+ */
+extern void nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *);
+extern void nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *, struct nfsd4_delegreturn *);
+extern void nfsd4_get_freestateid(struct nfsd4_compound_state *, struct nfsd4_free_stateid *);
+extern void nfsd4_get_setattrstateid(struct nfsd4_compound_state *, struct nfsd4_setattr *);
+extern void nfsd4_get_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *);
+extern void nfsd4_get_lockustateid(struct nfsd4_compound_state *, struct nfsd4_locku *);
+extern void nfsd4_get_readstateid(struct nfsd4_compound_state *, struct nfsd4_read *);
+extern void nfsd4_get_writestateid(struct nfsd4_compound_state *, struct nfsd4_write *);
+
+#endif   /* _NFSD4_CURRENT_STATE_H */
index cf8a6bd062fa9dc4eccdf3ecc464d83b2a8a6366..8e9689abbc0c7594fb6aa6cb7fb7735018165162 100644 (file)
@@ -87,7 +87,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
        struct svc_expkey key;
        struct svc_expkey *ek = NULL;
 
-       if (mlen < 1 || mesg[mlen-1] != '\n')
+       if (mesg[mlen - 1] != '\n')
                return -EINVAL;
        mesg[mlen-1] = 0;
 
index 0e262f32ac415a577793c74bb8cf6e7cd8d9202f..cf6e4190e41c7963d2f024525b9b3b99ce24728f 100644 (file)
@@ -986,7 +986,7 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
 
        err = setup_callback_client(clp, &conn, ses);
        if (err) {
-               warn_no_callback_path(clp, err);
+               nfsd4_mark_cb_down(clp, err);
                return;
        }
        /* Yay, the callback channel's back! Restart any callbacks: */
index 896da74ec5634fd92739e0284f5d0768c8f12437..2a9036670b8fcb776ae791a3f71224925c9bca12 100644 (file)
@@ -39,6 +39,7 @@
 #include "cache.h"
 #include "xdr4.h"
 #include "vfs.h"
+#include "current_stateid.h"
 
 #define NFSDDBG_FACILITY               NFSDDBG_PROC
 
@@ -192,10 +193,13 @@ static __be32 nfsd_check_obj_isreg(struct svc_fh *fh)
 static __be32
 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
-       struct svc_fh resfh;
+       struct svc_fh *resfh;
        __be32 status;
 
-       fh_init(&resfh, NFS4_FHSIZE);
+       resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
+       if (!resfh)
+               return nfserr_jukebox;
+       fh_init(resfh, NFS4_FHSIZE);
        open->op_truncate = 0;
 
        if (open->op_create) {
@@ -220,7 +224,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
                 */
                status = do_nfsd_create(rqstp, current_fh, open->op_fname.data,
                                        open->op_fname.len, &open->op_iattr,
-                                       &resfh, open->op_createmode,
+                                       resfh, open->op_createmode,
                                        (u32 *)open->op_verf.data,
                                        &open->op_truncate, &open->op_created);
 
@@ -234,30 +238,29 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
                                                FATTR4_WORD1_TIME_MODIFY);
        } else {
                status = nfsd_lookup(rqstp, current_fh,
-                                    open->op_fname.data, open->op_fname.len, &resfh);
+                                    open->op_fname.data, open->op_fname.len, resfh);
                fh_unlock(current_fh);
                if (status)
                        goto out;
-               status = nfsd_check_obj_isreg(&resfh);
+               status = nfsd_check_obj_isreg(resfh);
        }
        if (status)
                goto out;
 
        if (is_create_with_attrs(open) && open->op_acl != NULL)
-               do_set_nfs4_acl(rqstp, &resfh, open->op_acl, open->op_bmval);
-
-       set_change_info(&open->op_cinfo, current_fh);
-       fh_dup2(current_fh, &resfh);
+               do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval);
 
        /* set reply cache */
        fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
-                       &resfh.fh_handle);
+                       &resfh->fh_handle);
        if (!open->op_created)
-               status = do_open_permission(rqstp, current_fh, open,
+               status = do_open_permission(rqstp, resfh, open,
                                            NFSD_MAY_NOP);
-
+       set_change_info(&open->op_cinfo, current_fh);
+       fh_dup2(current_fh, resfh);
 out:
-       fh_put(&resfh);
+       fh_put(resfh);
+       kfree(resfh);
        return status;
 }
 
@@ -310,9 +313,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
                return nfserr_inval;
 
-       /* We don't yet support WANT bits: */
-       open->op_share_access &= NFS4_SHARE_ACCESS_MASK;
-
        open->op_created = 0;
        /*
         * RFC5661 18.51.3
@@ -452,6 +452,10 @@ nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                return nfserr_restorefh;
 
        fh_dup2(&cstate->current_fh, &cstate->save_fh);
+       if (HAS_STATE_ID(cstate, SAVED_STATE_ID_FLAG)) {
+               memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t));
+               SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+       }
        return nfs_ok;
 }
 
@@ -463,6 +467,10 @@ nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                return nfserr_nofilehandle;
 
        fh_dup2(&cstate->save_fh, &cstate->current_fh);
+       if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) {
+               memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t));
+               SET_STATE_ID(cstate, SAVED_STATE_ID_FLAG);
+       }
        return nfs_ok;
 }
 
@@ -481,14 +489,20 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                           &access->ac_supported);
 }
 
+static void gen_boot_verifier(nfs4_verifier *verifier)
+{
+       __be32 verf[2];
+
+       verf[0] = (__be32)nfssvc_boot.tv_sec;
+       verf[1] = (__be32)nfssvc_boot.tv_usec;
+       memcpy(verifier->data, verf, sizeof(verifier->data));
+}
+
 static __be32
 nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
             struct nfsd4_commit *commit)
 {
-       u32 *p = (u32 *)commit->co_verf.data;
-       *p++ = nfssvc_boot.tv_sec;
-       *p++ = nfssvc_boot.tv_usec;
-
+       gen_boot_verifier(&commit->co_verf);
        return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
                             commit->co_count);
 }
@@ -865,7 +879,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
        stateid_t *stateid = &write->wr_stateid;
        struct file *filp = NULL;
-       u32 *p;
        __be32 status = nfs_ok;
        unsigned long cnt;
 
@@ -887,9 +900,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        cnt = write->wr_buflen;
        write->wr_how_written = write->wr_stable_how;
-       p = (u32 *)write->wr_verifier.data;
-       *p++ = nfssvc_boot.tv_sec;
-       *p++ = nfssvc_boot.tv_usec;
+       gen_boot_verifier(&write->wr_verifier);
 
        status =  nfsd_write(rqstp, &cstate->current_fh, filp,
                             write->wr_offset, rqstp->rq_vec, write->wr_vlen,
@@ -1000,6 +1011,8 @@ static inline void nfsd4_increment_op_stats(u32 opnum)
 typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
                              void *);
 typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op);
+typedef void(*stateid_setter)(struct nfsd4_compound_state *, void *);
+typedef void(*stateid_getter)(struct nfsd4_compound_state *, void *);
 
 enum nfsd4_op_flags {
        ALLOWED_WITHOUT_FH = 1 << 0,    /* No current filehandle required */
@@ -1025,6 +1038,10 @@ enum nfsd4_op_flags {
         * the v4.0 case).
         */
        OP_CACHEME = 1 << 6,
+       /*
+        * These are ops which clear current state id.
+        */
+       OP_CLEAR_STATEID = 1 << 7,
 };
 
 struct nfsd4_operation {
@@ -1033,11 +1050,15 @@ struct nfsd4_operation {
        char *op_name;
        /* Try to get response size before operation */
        nfsd4op_rsize op_rsize_bop;
+       stateid_setter op_get_currentstateid;
+       stateid_getter op_set_currentstateid;
 };
 
 static struct nfsd4_operation nfsd4_ops[];
 
+#ifdef NFSD_DEBUG
 static const char *nfsd4_op_name(unsigned opnum);
+#endif
 
 /*
  * Enforce NFSv4.1 COMPOUND ordering rules:
@@ -1215,13 +1236,23 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
                if (op->status)
                        goto encode_op;
 
-               if (opdesc->op_func)
+               if (opdesc->op_func) {
+                       if (opdesc->op_get_currentstateid)
+                               opdesc->op_get_currentstateid(cstate, &op->u);
                        op->status = opdesc->op_func(rqstp, cstate, &op->u);
-               else
+               else
                        BUG_ON(op->status == nfs_ok);
 
-               if (!op->status && need_wrongsec_check(rqstp))
-                       op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp);
+               if (!op->status) {
+                       if (opdesc->op_set_currentstateid)
+                               opdesc->op_set_currentstateid(cstate, &op->u);
+
+                       if (opdesc->op_flags & OP_CLEAR_STATEID)
+                               clear_current_stateid(cstate);
+
+                       if (need_wrongsec_check(rqstp))
+                               op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp);
+               }
 
 encode_op:
                /* Only from SEQUENCE */
@@ -1413,6 +1444,8 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_CLOSE",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
+               .op_get_currentstateid = (stateid_getter)nfsd4_get_closestateid,
+               .op_set_currentstateid = (stateid_setter)nfsd4_set_closestateid,
        },
        [OP_COMMIT] = {
                .op_func = (nfsd4op_func)nfsd4_commit,
@@ -1422,7 +1455,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
        },
        [OP_CREATE] = {
                .op_func = (nfsd4op_func)nfsd4_create,
-               .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+               .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME | OP_CLEAR_STATEID,
                .op_name = "OP_CREATE",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize,
        },
@@ -1431,6 +1464,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_DELEGRETURN",
                .op_rsize_bop = nfsd4_only_status_rsize,
+               .op_get_currentstateid = (stateid_getter)nfsd4_get_delegreturnstateid,
        },
        [OP_GETATTR] = {
                .op_func = (nfsd4op_func)nfsd4_getattr,
@@ -1453,6 +1487,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_LOCK",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize,
+               .op_set_currentstateid = (stateid_setter)nfsd4_set_lockstateid,
        },
        [OP_LOCKT] = {
                .op_func = (nfsd4op_func)nfsd4_lockt,
@@ -1463,15 +1498,16 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_LOCKU",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
+               .op_get_currentstateid = (stateid_getter)nfsd4_get_lockustateid,
        },
        [OP_LOOKUP] = {
                .op_func = (nfsd4op_func)nfsd4_lookup,
-               .op_flags = OP_HANDLES_WRONGSEC,
+               .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
                .op_name = "OP_LOOKUP",
        },
        [OP_LOOKUPP] = {
                .op_func = (nfsd4op_func)nfsd4_lookupp,
-               .op_flags = OP_HANDLES_WRONGSEC,
+               .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
                .op_name = "OP_LOOKUPP",
        },
        [OP_NVERIFY] = {
@@ -1483,6 +1519,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
                .op_name = "OP_OPEN",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize,
+               .op_set_currentstateid = (stateid_setter)nfsd4_set_openstateid,
        },
        [OP_OPEN_CONFIRM] = {
                .op_func = (nfsd4op_func)nfsd4_open_confirm,
@@ -1495,25 +1532,30 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_OPEN_DOWNGRADE",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
+               .op_get_currentstateid = (stateid_getter)nfsd4_get_opendowngradestateid,
+               .op_set_currentstateid = (stateid_setter)nfsd4_set_opendowngradestateid,
        },
        [OP_PUTFH] = {
                .op_func = (nfsd4op_func)nfsd4_putfh,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
-                               | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
+                               | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING
+                               | OP_CLEAR_STATEID,
                .op_name = "OP_PUTFH",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
        },
        [OP_PUTPUBFH] = {
                .op_func = (nfsd4op_func)nfsd4_putrootfh,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
-                               | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
+                               | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING
+                               | OP_CLEAR_STATEID,
                .op_name = "OP_PUTPUBFH",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
        },
        [OP_PUTROOTFH] = {
                .op_func = (nfsd4op_func)nfsd4_putrootfh,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
-                               | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
+                               | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING
+                               | OP_CLEAR_STATEID,
                .op_name = "OP_PUTROOTFH",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
        },
@@ -1522,6 +1564,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = OP_MODIFIES_SOMETHING,
                .op_name = "OP_READ",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize,
+               .op_get_currentstateid = (stateid_getter)nfsd4_get_readstateid,
        },
        [OP_READDIR] = {
                .op_func = (nfsd4op_func)nfsd4_readdir,
@@ -1576,6 +1619,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_name = "OP_SETATTR",
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize,
+               .op_get_currentstateid = (stateid_getter)nfsd4_get_setattrstateid,
        },
        [OP_SETCLIENTID] = {
                .op_func = (nfsd4op_func)nfsd4_setclientid,
@@ -1600,6 +1644,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
                .op_name = "OP_WRITE",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
+               .op_get_currentstateid = (stateid_getter)nfsd4_get_writestateid,
        },
        [OP_RELEASE_LOCKOWNER] = {
                .op_func = (nfsd4op_func)nfsd4_release_lockowner,
@@ -1674,12 +1719,14 @@ static struct nfsd4_operation nfsd4_ops[] = {
        },
 };
 
+#ifdef NFSD_DEBUG
 static const char *nfsd4_op_name(unsigned opnum)
 {
        if (opnum < ARRAY_SIZE(nfsd4_ops))
                return nfsd4_ops[opnum].op_name;
        return "unknown_operation";
 }
+#endif
 
 #define nfsd4_voidres                  nfsd4_voidargs
 struct nfsd4_voidargs { int dummy; };
index c5cddd659429f33b371ea03a3d920808911ce8f1..a0a2b535b0e0f82f5e88d6a204fb584e2eefa563 100644 (file)
@@ -58,11 +58,15 @@ static const stateid_t one_stateid = {
 static const stateid_t zero_stateid = {
        /* all fields zero */
 };
+static const stateid_t currentstateid = {
+       .si_generation = 1,
+};
 
 static u64 current_sessionid = 1;
 
 #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
 #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
+#define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
 
 /* forward declarations */
 static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
@@ -91,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)
 {
@@ -605,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)
@@ -832,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);
@@ -847,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;
@@ -894,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) {
@@ -1006,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);
@@ -1138,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)
@@ -1180,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;
                }
        }
@@ -1347,6 +1385,7 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
        slot->sl_opcnt = resp->opcnt;
        slot->sl_status = resp->cstate.status;
 
+       slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
        if (nfsd4_not_cached(resp)) {
                slot->sl_datalen = 0;
                return;
@@ -1374,15 +1413,12 @@ nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
        struct nfsd4_op *op;
        struct nfsd4_slot *slot = resp->cstate.slot;
 
-       dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__,
-               resp->opcnt, resp->cstate.slot->sl_cachethis);
-
        /* Encode the replayed sequence operation */
        op = &args->ops[resp->opcnt - 1];
        nfsd4_encode_operation(resp, op);
 
        /* Return nfserr_retry_uncached_rep in next operation. */
-       if (args->opcnt > 1 && slot->sl_cachethis == 0) {
+       if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
                op = &args->ops[resp->opcnt++];
                op->status = nfserr_retry_uncached_rep;
                nfsd4_encode_operation(resp, op);
@@ -1575,16 +1611,11 @@ check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
                else
                        return nfserr_seq_misordered;
        }
-       /* Normal */
+       /* Note unsigned 32-bit arithmetic handles wraparound: */
        if (likely(seqid == slot_seqid + 1))
                return nfs_ok;
-       /* Replay */
        if (seqid == slot_seqid)
                return nfserr_replay_cache;
-       /* Wraparound */
-       if (seqid == 1 && (slot_seqid + 1) == 0)
-               return nfs_ok;
-       /* Misordered replay or misordered new request */
        return nfserr_seq_misordered;
 }
 
@@ -1815,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));
@@ -1921,8 +1953,12 @@ nfsd4_sequence(struct svc_rqst *rqstp,
         * sr_highest_slotid and the sr_target_slot id to maxslots */
        seq->maxslots = session->se_fchannel.maxreqs;
 
-       status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse);
+       status = check_slot_seqid(seq->seqid, slot->sl_seqid,
+                                       slot->sl_flags & NFSD4_SLOT_INUSE);
        if (status == nfserr_replay_cache) {
+               status = nfserr_seq_misordered;
+               if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
+                       goto out;
                cstate->slot = slot;
                cstate->session = session;
                /* Return the cached reply status and set cstate->status
@@ -1938,9 +1974,12 @@ nfsd4_sequence(struct svc_rqst *rqstp,
        conn = NULL;
 
        /* Success! bump slot seqid */
-       slot->sl_inuse = true;
        slot->sl_seqid = seq->seqid;
-       slot->sl_cachethis = seq->cachethis;
+       slot->sl_flags |= NFSD4_SLOT_INUSE;
+       if (seq->cachethis)
+               slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
+       else
+               slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS;
 
        cstate->slot = slot;
        cstate->session = session;
@@ -2633,8 +2672,6 @@ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
 
 static 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;
 }
 
@@ -2776,10 +2813,15 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c
 
 
 static void
-nfs4_set_claim_prev(struct nfsd4_open *open)
+nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session)
 {
        open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
-       open->op_openowner->oo_owner.so_client->cl_firststate = 1;
+       /*
+        * On a 4.1+ client, we don't create a state record for a client
+        * until it performs RECLAIM_COMPLETE:
+        */
+       if (!has_session)
+               open->op_openowner->oo_owner.so_client->cl_firststate = 1;
 }
 
 /* Should we give out recallable state?: */
@@ -2855,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.
  */
@@ -2864,7 +2927,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_
        struct nfs4_delegation *dp;
        struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
        int cb_up;
-       int status, flag = 0;
+       int status = 0, flag = 0;
 
        cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
        flag = NFS4_OPEN_DELEGATE_NONE;
@@ -2905,11 +2968,16 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_
        dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
                STATEID_VAL(&dp->dl_stid.sc_stateid));
 out:
-       if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
-                       && flag == NFS4_OPEN_DELEGATE_NONE
-                       && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
-               dprintk("NFSD: WARNING: refusing delegation reclaim\n");
        open->op_delegate_type = flag;
+       if (flag == NFS4_OPEN_DELEGATE_NONE) {
+               if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
+                   open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
+                       dprintk("NFSD: WARNING: refusing delegation reclaim\n");
+
+               /* 4.1 client asking for a delegation? */
+               if (open->op_deleg_want)
+                       nfsd4_open_deleg_none_ext(open, status);
+       }
        return;
 out_free:
        nfs4_put_delegation(dp);
@@ -2918,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.
  */
@@ -2979,24 +3065,36 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
        update_stateid(&stp->st_stid.sc_stateid);
        memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 
-       if (nfsd4_has_session(&resp->cstate))
+       if (nfsd4_has_session(&resp->cstate)) {
                open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
 
+               if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
+                       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+                       open->op_why_no_deleg = WND4_NOT_WANTED;
+                       goto nodeleg;
+               }
+       }
+
        /*
        * Attempt to hand out a delegation. No error return, because the
        * OPEN succeeds even if we fail.
        */
        nfs4_open_delegation(current_fh, open, stp);
-
+nodeleg:
        status = nfs_ok;
 
        dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
                STATEID_VAL(&stp->st_stid.sc_stateid));
 out:
+       /* 4.1 client trying to upgrade/downgrade delegation? */
+       if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
+           open->op_deleg_want)
+               nfsd4_deleg_xgrade_none_ext(open, dp);
+
        if (fp)
                put_nfs4_file(fp);
        if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
-               nfs4_set_claim_prev(open);
+               nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate));
        /*
        * To finish the open response, we just need to set the rflags.
        */
@@ -3400,7 +3498,14 @@ __be32
 nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                   struct nfsd4_test_stateid *test_stateid)
 {
-       /* real work is done during encoding */
+       struct nfsd4_test_stateid_id *stateid;
+       struct nfs4_client *cl = cstate->session->se_client;
+
+       nfs4_lock_state();
+       list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
+               stateid->ts_id_status = nfs4_validate_stateid(cl, &stateid->ts_id_stateid);
+       nfs4_unlock_state();
+
        return nfs_ok;
 }
 
@@ -3596,7 +3701,9 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
                        cstate->current_fh.fh_dentry->d_name.name);
 
        /* We don't yet support WANT bits: */
-       od->od_share_access &= NFS4_SHARE_ACCESS_MASK;
+       if (od->od_deleg_want)
+               dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
+                       od->od_deleg_want);
 
        nfs4_lock_state();
        status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
@@ -4353,7 +4460,9 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id)
        struct nfs4_client *clp;
 
        clp = find_confirmed_client_by_str(name, strhashval);
-       return clp ? 1 : 0;
+       if (!clp)
+               return 0;
+       return clp->cl_firststate;
 }
 
 /*
@@ -4613,21 +4722,26 @@ set_max_delegations(void)
 
 /* initialization to perform when the nfsd service is started: */
 
-static int
-__nfs4_state_start(void)
+int
+nfs4_state_start(void)
 {
        int ret;
 
+       nfsd4_load_reboot_recovery_data();
        boot_time = get_seconds();
        locks_start_grace(&nfsd4_manager);
        printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
               nfsd4_grace);
        ret = set_callback_cred();
-       if (ret)
-               return -ENOMEM;
+       if (ret) {
+               ret = -ENOMEM;
+               goto out_recovery;
+       }
        laundry_wq = create_singlethread_workqueue("nfsd4");
-       if (laundry_wq == NULL)
-               return -ENOMEM;
+       if (laundry_wq == NULL) {
+               ret = -ENOMEM;
+               goto out_recovery;
+       }
        ret = nfsd4_create_callback_queue();
        if (ret)
                goto out_free_laundry;
@@ -4636,16 +4750,12 @@ __nfs4_state_start(void)
        return 0;
 out_free_laundry:
        destroy_workqueue(laundry_wq);
+out_recovery:
+       nfs4_release_reclaim();
+       nfsd4_shutdown_recdir();
        return ret;
 }
 
-int
-nfs4_state_start(void)
-{
-       nfsd4_load_reboot_recovery_data();
-       return __nfs4_state_start();
-}
-
 static void
 __nfs4_state_shutdown(void)
 {
@@ -4691,3 +4801,104 @@ nfs4_state_shutdown(void)
        nfs4_unlock_state();
        nfsd4_destroy_callback_queue();
 }
+
+static void
+get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
+{
+       if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
+               memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
+}
+
+static void
+put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
+{
+       if (cstate->minorversion) {
+               memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
+               SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+       }
+}
+
+void
+clear_current_stateid(struct nfsd4_compound_state *cstate)
+{
+       CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+}
+
+/*
+ * functions to set current state id
+ */
+void
+nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
+{
+       put_stateid(cstate, &odp->od_stateid);
+}
+
+void
+nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
+{
+       put_stateid(cstate, &open->op_stateid);
+}
+
+void
+nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
+{
+       put_stateid(cstate, &close->cl_stateid);
+}
+
+void
+nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock)
+{
+       put_stateid(cstate, &lock->lk_resp_stateid);
+}
+
+/*
+ * functions to consume current state id
+ */
+
+void
+nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
+{
+       get_stateid(cstate, &odp->od_stateid);
+}
+
+void
+nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp)
+{
+       get_stateid(cstate, &drp->dr_stateid);
+}
+
+void
+nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp)
+{
+       get_stateid(cstate, &fsp->fr_stateid);
+}
+
+void
+nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr)
+{
+       get_stateid(cstate, &setattr->sa_stateid);
+}
+
+void
+nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
+{
+       get_stateid(cstate, &close->cl_stateid);
+}
+
+void
+nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku)
+{
+       get_stateid(cstate, &locku->lu_stateid);
+}
+
+void
+nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read)
+{
+       get_stateid(cstate, &read->rd_stateid);
+}
+
+void
+nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write)
+{
+       get_stateid(cstate, &write->wr_stateid);
+}
index 0ec5a1b9700e5e8d59196cfa387f608aa5c7f0ce..bcd8904ab1e36dd807f26379392000fb114f9bc6 100644 (file)
@@ -133,22 +133,6 @@ xdr_error:                                 \
        }                                       \
 } while (0)
 
-static void save_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
-{
-       savep->p        = argp->p;
-       savep->end      = argp->end;
-       savep->pagelen  = argp->pagelen;
-       savep->pagelist = argp->pagelist;
-}
-
-static void restore_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
-{
-       argp->p        = savep->p;
-       argp->end      = savep->end;
-       argp->pagelen  = savep->pagelen;
-       argp->pagelist = savep->pagelist;
-}
-
 static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
 {
        /* We want more bytes than seem to be available.
@@ -638,14 +622,18 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup
        DECODE_TAIL;
 }
 
-static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *x)
+static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when)
 {
        __be32 *p;
        u32 w;
 
        READ_BUF(4);
        READ32(w);
-       *x = w;
+       *share_access = w & NFS4_SHARE_ACCESS_MASK;
+       *deleg_want = w & NFS4_SHARE_WANT_MASK;
+       if (deleg_when)
+               *deleg_when = w & NFS4_SHARE_WHEN_MASK;
+
        switch (w & NFS4_SHARE_ACCESS_MASK) {
        case NFS4_SHARE_ACCESS_READ:
        case NFS4_SHARE_ACCESS_WRITE:
@@ -673,6 +661,9 @@ static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *x)
        w &= ~NFS4_SHARE_WANT_MASK;
        if (!w)
                return nfs_ok;
+
+       if (!deleg_when)        /* open_downgrade */
+               return nfserr_inval;
        switch (w) {
        case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL:
        case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED:
@@ -719,6 +710,7 @@ static __be32
 nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
 {
        DECODE_HEAD;
+       u32 dummy;
 
        memset(open->op_bmval, 0, sizeof(open->op_bmval));
        open->op_iattr.ia_valid = 0;
@@ -727,7 +719,9 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
        /* seqid, share_access, share_deny, clientid, ownerlen */
        READ_BUF(4);
        READ32(open->op_seqid);
-       status = nfsd4_decode_share_access(argp, &open->op_share_access);
+       /* decode, yet ignore deleg_when until supported */
+       status = nfsd4_decode_share_access(argp, &open->op_share_access,
+                                          &open->op_deleg_want, &dummy);
        if (status)
                goto xdr_error;
        status = nfsd4_decode_share_deny(argp, &open->op_share_deny);
@@ -755,14 +749,14 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
                                goto out;
                        break;
                case NFS4_CREATE_EXCLUSIVE:
-                       READ_BUF(8);
-                       COPYMEM(open->op_verf.data, 8);
+                       READ_BUF(NFS4_VERIFIER_SIZE);
+                       COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
                        break;
                case NFS4_CREATE_EXCLUSIVE4_1:
                        if (argp->minorversion < 1)
                                goto xdr_error;
-                       READ_BUF(8);
-                       COPYMEM(open->op_verf.data, 8);
+                       READ_BUF(NFS4_VERIFIER_SIZE);
+                       COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
                        status = nfsd4_decode_fattr(argp, open->op_bmval,
                                &open->op_iattr, &open->op_acl);
                        if (status)
@@ -848,7 +842,8 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d
                return status;
        READ_BUF(4);
        READ32(open_down->od_seqid);
-       status = nfsd4_decode_share_access(argp, &open_down->od_share_access);
+       status = nfsd4_decode_share_access(argp, &open_down->od_share_access,
+                                          &open_down->od_deleg_want, NULL);
        if (status)
                return status;
        status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny);
@@ -994,8 +989,8 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient
 {
        DECODE_HEAD;
 
-       READ_BUF(8);
-       COPYMEM(setclientid->se_verf.data, 8);
+       READ_BUF(NFS4_VERIFIER_SIZE);
+       COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE);
 
        status = nfsd4_decode_opaque(argp, &setclientid->se_name);
        if (status)
@@ -1020,9 +1015,9 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s
 {
        DECODE_HEAD;
 
-       READ_BUF(8 + sizeof(nfs4_verifier));
+       READ_BUF(8 + NFS4_VERIFIER_SIZE);
        COPYMEM(&scd_c->sc_clientid, 8);
-       COPYMEM(&scd_c->sc_confirm, sizeof(nfs4_verifier));
+       COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE);
 
        DECODE_TAIL;
 }
@@ -1385,26 +1380,29 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
 static __be32
 nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
 {
-       unsigned int nbytes;
-       stateid_t si;
        int i;
-       __be32 *p;
-       __be32 status;
+       __be32 *p, status;
+       struct nfsd4_test_stateid_id *stateid;
 
        READ_BUF(4);
        test_stateid->ts_num_ids = ntohl(*p++);
 
-       nbytes = test_stateid->ts_num_ids * sizeof(stateid_t);
-       if (nbytes > (u32)((char *)argp->end - (char *)argp->p))
-               goto xdr_error;
-
-       test_stateid->ts_saved_args = argp;
-       save_buf(argp, &test_stateid->ts_savedp);
+       INIT_LIST_HEAD(&test_stateid->ts_stateid_list);
 
        for (i = 0; i < test_stateid->ts_num_ids; i++) {
-               status = nfsd4_decode_stateid(argp, &si);
+               stateid = kmalloc(sizeof(struct nfsd4_test_stateid_id), GFP_KERNEL);
+               if (!stateid) {
+                       status = PTR_ERR(stateid);
+                       goto out;
+               }
+
+               defer_free(argp, kfree, stateid);
+               INIT_LIST_HEAD(&stateid->ts_id_list);
+               list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
+
+               status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid);
                if (status)
-                       return status;
+                       goto out;
        }
 
        status = 0;
@@ -2661,8 +2659,8 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
        __be32 *p;
 
        if (!nfserr) {
-               RESERVE_SPACE(8);
-               WRITEMEM(commit->co_verf.data, 8);
+               RESERVE_SPACE(NFS4_VERIFIER_SIZE);
+               WRITEMEM(commit->co_verf.data, NFS4_VERIFIER_SIZE);
                ADJUST_ARGS();
        }
        return nfserr;
@@ -2851,6 +2849,20 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
                WRITE32(0);   /* XXX: is NULL principal ok? */
                ADJUST_ARGS();
                break;
+       case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */
+               switch (open->op_why_no_deleg) {
+               case WND4_CONTENTION:
+               case WND4_RESOURCE:
+                       RESERVE_SPACE(8);
+                       WRITE32(open->op_why_no_deleg);
+                       WRITE32(0);     /* deleg signaling not supported yet */
+                       break;
+               default:
+                       RESERVE_SPACE(4);
+                       WRITE32(open->op_why_no_deleg);
+               }
+               ADJUST_ARGS();
+               break;
        default:
                BUG();
        }
@@ -3008,7 +3020,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
        if (resp->xbuf->page_len)
                return nfserr_resource;
 
-       RESERVE_SPACE(8);  /* verifier */
+       RESERVE_SPACE(NFS4_VERIFIER_SIZE);
        savep = p;
 
        /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
@@ -3209,9 +3221,9 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n
        __be32 *p;
 
        if (!nfserr) {
-               RESERVE_SPACE(8 + sizeof(nfs4_verifier));
+               RESERVE_SPACE(8 + NFS4_VERIFIER_SIZE);
                WRITEMEM(&scd->se_clientid, 8);
-               WRITEMEM(&scd->se_confirm, sizeof(nfs4_verifier));
+               WRITEMEM(&scd->se_confirm, NFS4_VERIFIER_SIZE);
                ADJUST_ARGS();
        }
        else if (nfserr == nfserr_clid_inuse) {
@@ -3232,7 +3244,7 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w
                RESERVE_SPACE(16);
                WRITE32(write->wr_bytes_written);
                WRITE32(write->wr_how_written);
-               WRITEMEM(write->wr_verifier.data, 8);
+               WRITEMEM(write->wr_verifier.data, NFS4_VERIFIER_SIZE);
                ADJUST_ARGS();
        }
        return nfserr;
@@ -3391,30 +3403,17 @@ __be32
 nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
                          struct nfsd4_test_stateid *test_stateid)
 {
-       struct nfsd4_compoundargs *argp;
-       struct nfs4_client *cl = resp->cstate.session->se_client;
-       stateid_t si;
+       struct nfsd4_test_stateid_id *stateid, *next;
        __be32 *p;
-       int i;
-       int valid;
-
-       restore_buf(test_stateid->ts_saved_args, &test_stateid->ts_savedp);
-       argp = test_stateid->ts_saved_args;
 
-       RESERVE_SPACE(4);
+       RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids));
        *p++ = htonl(test_stateid->ts_num_ids);
-       resp->p = p;
 
-       nfs4_lock_state();
-       for (i = 0; i < test_stateid->ts_num_ids; i++) {
-               nfsd4_decode_stateid(argp, &si);
-               valid = nfs4_validate_stateid(cl, &si);
-               RESERVE_SPACE(4);
-               *p++ = htonl(valid);
-               resp->p = p;
+       list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) {
+               *p++ = htonl(stateid->ts_id_status);
        }
-       nfs4_unlock_state();
 
+       ADJUST_ARGS();
        return nfserr;
 }
 
@@ -3532,7 +3531,7 @@ int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
        if (length > session->se_fchannel.maxresp_sz)
                return nfserr_rep_too_big;
 
-       if (slot->sl_cachethis == 1 &&
+       if ((slot->sl_flags & NFSD4_SLOT_CACHETHIS) &&
            length > session->se_fchannel.maxresp_cached)
                return nfserr_rep_too_big_to_cache;
 
@@ -3656,8 +3655,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
        if (nfsd4_has_session(cs)) {
                if (cs->status != nfserr_replay_cache) {
                        nfsd4_store_cache_entry(resp);
-                       dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
-                       cs->slot->sl_inuse = false;
+                       cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
                }
                /* Renew the clientid on success and on replay */
                release_session_client(cs->session);
index fce472f5f39e74f2fb9ab36bdf70019f573a73af..28dfad39f0c50a626384c4363955e2b9d7e3212f 100644 (file)
@@ -307,33 +307,37 @@ static void set_max_drc(void)
        dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem);
 }
 
-int nfsd_create_serv(void)
+static int nfsd_get_default_max_blksize(void)
 {
-       int err = 0;
+       struct sysinfo i;
+       unsigned long long target;
+       unsigned long ret;
+
+       si_meminfo(&i);
+       target = (i.totalram - i.totalhigh) << PAGE_SHIFT;
+       /*
+        * Aim for 1/4096 of memory per thread This gives 1MB on 4Gig
+        * machines, but only uses 32K on 128M machines.  Bottom out at
+        * 8K on 32M and smaller.  Of course, this is only a default.
+        */
+       target >>= 12;
+
+       ret = NFSSVC_MAXBLKSIZE;
+       while (ret > target && ret >= 8*1024*2)
+               ret /= 2;
+       return ret;
+}
 
+int nfsd_create_serv(void)
+{
        WARN_ON(!mutex_is_locked(&nfsd_mutex));
        if (nfsd_serv) {
                svc_get(nfsd_serv);
                return 0;
        }
-       if (nfsd_max_blksize == 0) {
-               /* choose a suitable default */
-               struct sysinfo i;
-               si_meminfo(&i);
-               /* Aim for 1/4096 of memory per thread
-                * This gives 1MB on 4Gig machines
-                * But only uses 32K on 128M machines.
-                * Bottom out at 8K on 32M and smaller.
-                * Of course, this is only a default.
-                */
-               nfsd_max_blksize = NFSSVC_MAXBLKSIZE;
-               i.totalram <<= PAGE_SHIFT - 12;
-               while (nfsd_max_blksize > i.totalram &&
-                      nfsd_max_blksize >= 8*1024*2)
-                       nfsd_max_blksize /= 2;
-       }
+       if (nfsd_max_blksize == 0)
+               nfsd_max_blksize = nfsd_get_default_max_blksize();
        nfsd_reset_versions();
-
        nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
                                      nfsd_last_thread, nfsd, THIS_MODULE);
        if (nfsd_serv == NULL)
@@ -341,7 +345,7 @@ int nfsd_create_serv(void)
 
        set_max_drc();
        do_gettimeofday(&nfssvc_boot);          /* record boot time */
-       return err;
+       return 0;
 }
 
 int nfsd_nrpools(void)
index ffb5df1db94ff86558aff1340a6b07af2af29b79..1e2b582bc9dc02326309ced2d932c98a69f5f122 100644 (file)
@@ -128,12 +128,14 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s)
                (NFSD_CACHE_SIZE_SLOTS_PER_SESSION * NFSD_SLOT_CACHE_SIZE)
 
 struct nfsd4_slot {
-       bool    sl_inuse;
-       bool    sl_cachethis;
-       u16     sl_opcnt;
        u32     sl_seqid;
        __be32  sl_status;
        u32     sl_datalen;
+       u16     sl_opcnt;
+#define NFSD4_SLOT_INUSE       (1 << 0)
+#define NFSD4_SLOT_CACHETHIS   (1 << 1)
+#define NFSD4_SLOT_INITIALIZED (1 << 2)
+       u8      sl_flags;
        char    sl_data[];
 };
 
@@ -196,18 +198,7 @@ struct nfsd4_session {
        struct nfsd4_slot       *se_slots[];    /* forward channel slots */
 };
 
-static inline void
-nfsd4_put_session(struct nfsd4_session *ses)
-{
-       extern void free_session(struct kref *kref);
-       kref_put(&ses->se_ref, free_session);
-}
-
-static inline void
-nfsd4_get_session(struct nfsd4_session *ses)
-{
-       kref_get(&ses->se_ref);
-}
+extern void nfsd4_put_session(struct nfsd4_session *ses);
 
 /* formatted contents of nfs4_sessionid */
 struct nfsd4_sessionid {
index edf6d3ed87778822d85c32929cab580c93ed3c7a..7423d712eb8c91f56dbf7c7c99d0bb8153fcb86c 100644 (file)
@@ -737,12 +737,13 @@ static int nfsd_open_break_lease(struct inode *inode, int access)
 
 /*
  * Open an existing file or directory.
- * The access argument indicates the type of open (read/write/lock)
+ * The may_flags argument indicates the type of open (read/write/lock)
+ * and additional flags.
  * N.B. After this call fhp needs an fh_put
  */
 __be32
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
-                       int access, struct file **filp)
+                       int may_flags, struct file **filp)
 {
        struct dentry   *dentry;
        struct inode    *inode;
@@ -757,7 +758,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
         * and (hopefully) checked permission - so allow OWNER_OVERRIDE
         * in case a chmod has now revoked permission.
         */
-       err = fh_verify(rqstp, fhp, type, access | NFSD_MAY_OWNER_OVERRIDE);
+       err = fh_verify(rqstp, fhp, type, may_flags | NFSD_MAY_OWNER_OVERRIDE);
        if (err)
                goto out;
 
@@ -768,7 +769,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
         * or any access when mandatory locking enabled
         */
        err = nfserr_perm;
-       if (IS_APPEND(inode) && (access & NFSD_MAY_WRITE))
+       if (IS_APPEND(inode) && (may_flags & NFSD_MAY_WRITE))
                goto out;
        /*
         * We must ignore files (but only files) which might have mandatory
@@ -781,12 +782,12 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
        if (!inode->i_fop)
                goto out;
 
-       host_err = nfsd_open_break_lease(inode, access);
+       host_err = nfsd_open_break_lease(inode, may_flags);
        if (host_err) /* NOMEM or WOULDBLOCK */
                goto out_nfserr;
 
-       if (access & NFSD_MAY_WRITE) {
-               if (access & NFSD_MAY_READ)
+       if (may_flags & NFSD_MAY_WRITE) {
+               if (may_flags & NFSD_MAY_READ)
                        flags = O_RDWR|O_LARGEFILE;
                else
                        flags = O_WRONLY|O_LARGEFILE;
@@ -795,8 +796,15 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
                            flags, current_cred());
        if (IS_ERR(*filp))
                host_err = PTR_ERR(*filp);
-       else
-               host_err = ima_file_check(*filp, access);
+       else {
+               host_err = ima_file_check(*filp, may_flags);
+
+               if (may_flags & NFSD_MAY_64BIT_COOKIE)
+                       (*filp)->f_mode |= FMODE_64BITHASH;
+               else
+                       (*filp)->f_mode |= FMODE_32BITHASH;
+       }
+
 out_nfserr:
        err = nfserrno(host_err);
 out:
@@ -2020,8 +2028,13 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
        __be32          err;
        struct file     *file;
        loff_t          offset = *offsetp;
+       int             may_flags = NFSD_MAY_READ;
+
+       /* NFSv2 only supports 32 bit cookies */
+       if (rqstp->rq_vers > 2)
+               may_flags |= NFSD_MAY_64BIT_COOKIE;
 
-       err = nfsd_open(rqstp, fhp, S_IFDIR, NFSD_MAY_READ, &file);
+       err = nfsd_open(rqstp, fhp, S_IFDIR, may_flags, &file);
        if (err)
                goto out;
 
index 1dcd238e11a09c1051148f4ce27d3d06bb7da26a..ec0611b2b738468fbc261b35f2190048680e67dd 100644 (file)
@@ -27,6 +27,8 @@
 #define NFSD_MAY_BYPASS_GSS            0x400
 #define NFSD_MAY_READ_IF_EXEC          0x800
 
+#define NFSD_MAY_64BIT_COOKIE          0x1000 /* 64 bit readdir cookies for >= NFSv3 */
+
 #define NFSD_MAY_CREATE                (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
 #define NFSD_MAY_REMOVE                (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
 
index 2364747ee97db68d9d14600c1e849127f4ab9a71..1b3501598ab5dbb4609ba19e4f7c3322b29f70ba 100644 (file)
 #define NFSD4_MAX_TAGLEN       128
 #define XDR_LEN(n)                     (((n) + 3) & ~3)
 
+#define CURRENT_STATE_ID_FLAG (1<<0)
+#define SAVED_STATE_ID_FLAG (1<<1)
+
+#define SET_STATE_ID(c, f) ((c)->sid_flags |= (f))
+#define HAS_STATE_ID(c, f) ((c)->sid_flags & (f))
+#define CLEAR_STATE_ID(c, f) ((c)->sid_flags &= ~(f))
+
 struct nfsd4_compound_state {
        struct svc_fh           current_fh;
        struct svc_fh           save_fh;
@@ -54,6 +61,10 @@ struct nfsd4_compound_state {
        size_t                  iovlen;
        u32                     minorversion;
        u32                     status;
+       stateid_t       current_stateid;
+       stateid_t       save_stateid;
+       /* to indicate current and saved state id presents */
+       u32             sid_flags;
 };
 
 static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs)
@@ -212,16 +223,19 @@ struct nfsd4_open {
        struct xdr_netobj op_fname;         /* request - everything but CLAIM_PREV */
        u32             op_delegate_type;   /* request - CLAIM_PREV only */
        stateid_t       op_delegate_stateid; /* request - response */
+       u32             op_why_no_deleg;    /* response - DELEG_NONE_EXT only */
        u32             op_create;          /* request */
        u32             op_createmode;      /* request */
        u32             op_bmval[3];        /* request */
        struct iattr    iattr;              /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */
-       nfs4_verifier   verf;               /* EXCLUSIVE4 */
+       nfs4_verifier   op_verf __attribute__((aligned(32)));
+                                           /* EXCLUSIVE4 */
        clientid_t      op_clientid;        /* request */
        struct xdr_netobj op_owner;           /* request */
        u32             op_seqid;           /* request */
        u32             op_share_access;    /* request */
        u32             op_share_deny;      /* request */
+       u32             op_deleg_want;      /* request */
        stateid_t       op_stateid;         /* response */
        u32             op_recall;          /* recall */
        struct nfsd4_change_info  op_cinfo; /* response */
@@ -234,7 +248,6 @@ struct nfsd4_open {
        struct nfs4_acl *op_acl;
 };
 #define op_iattr       iattr
-#define op_verf                verf
 
 struct nfsd4_open_confirm {
        stateid_t       oc_req_stateid          /* request */;
@@ -245,8 +258,9 @@ struct nfsd4_open_confirm {
 struct nfsd4_open_downgrade {
        stateid_t       od_stateid;
        u32             od_seqid;
-       u32             od_share_access;
-       u32             od_share_deny;
+       u32             od_share_access;        /* request */
+       u32             od_deleg_want;          /* request */
+       u32             od_share_deny;          /* request */
 };
 
 
@@ -343,10 +357,15 @@ struct nfsd4_saved_compoundargs {
        struct page **pagelist;
 };
 
+struct nfsd4_test_stateid_id {
+       __be32                  ts_id_status;
+       stateid_t               ts_id_stateid;
+       struct list_head        ts_id_list;
+};
+
 struct nfsd4_test_stateid {
        __be32          ts_num_ids;
-       struct nfsd4_compoundargs *ts_saved_args;
-       struct nfsd4_saved_compoundargs ts_savedp;
+       struct list_head ts_stateid_list;
 };
 
 struct nfsd4_free_stateid {
@@ -503,7 +522,8 @@ static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp)
 
 static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
 {
-       return !resp->cstate.slot->sl_cachethis || nfsd4_is_solo_sequence(resp);
+       return !(resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
+               || nfsd4_is_solo_sequence(resp);
 }
 
 #define NFS4_SVC_XDRSIZE               sizeof(struct nfsd4_compoundargs)
index 386da09f229dfad8ff8ef5600c8045f221ae862f..8975a5602931335e9acaf312dd4ae3812e33c269 100644 (file)
@@ -92,6 +92,10 @@ struct inodes_stat_t {
 /* File is opened using open(.., 3, ..) and is writeable only for ioctls
    (specialy hack for floppy.c) */
 #define FMODE_WRITE_IOCTL      ((__force fmode_t)0x100)
+/* 32bit hashes as llseek() offset (for directories) */
+#define FMODE_32BITHASH         ((__force fmode_t)0x200)
+/* 64bit hashes as llseek() offset (for directories) */
+#define FMODE_64BITHASH         ((__force fmode_t)0x400)
 
 /*
  * Don't update ctime and mtime.
index 834df8bf08b6e54951bc6483f0ffecbc47c7bd28..0987146b0637a1fd1f9a4ea03fb7040b1d4314cd 100644 (file)
@@ -438,7 +438,20 @@ enum limit_by4 {
 enum open_delegation_type4 {
        NFS4_OPEN_DELEGATE_NONE = 0,
        NFS4_OPEN_DELEGATE_READ = 1,
-       NFS4_OPEN_DELEGATE_WRITE = 2
+       NFS4_OPEN_DELEGATE_WRITE = 2,
+       NFS4_OPEN_DELEGATE_NONE_EXT = 3, /* 4.1 */
+};
+
+enum why_no_delegation4 { /* new to v4.1 */
+       WND4_NOT_WANTED = 0,
+       WND4_CONTENTION = 1,
+       WND4_RESOURCE = 2,
+       WND4_NOT_SUPP_FTYPE = 3,
+       WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4,
+       WND4_NOT_SUPP_UPGRADE = 5,
+       WND4_NOT_SUPP_DOWNGRADE = 6,
+       WND4_CANCELLED = 7,
+       WND4_IS_DIR = 8,
 };
 
 enum lock_type4 {
index c14fe86dac594f069a08342f1790c03909586c41..0b8e3e6bdacf0b6af2e32541d6ad83cf52af8f6e 100644 (file)
@@ -190,7 +190,7 @@ extern int svc_rdma_xdr_encode_error(struct svcxprt_rdma *,
 extern void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *, int);
 extern void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *, int);
 extern void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *, int,
-                                           u32, u64, u32);
+                                           __be32, __be64, u32);
 extern void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *,
                                             struct rpcrdma_msg *,
                                             struct rpcrdma_msg *,
@@ -292,7 +292,7 @@ svc_rdma_get_reply_array(struct rpcrdma_msg *rmsgp)
        if (wr_ary) {
                rp_ary = (struct rpcrdma_write_array *)
                        &wr_ary->
-                       wc_array[wr_ary->wc_nchunks].wc_target.rs_length;
+                       wc_array[ntohl(wr_ary->wc_nchunks)].wc_target.rs_length;
 
                goto found_it;
        }
index f21ece08876440d574dad1ac6a09cf22d40d043e..de0b0f39d9d85430f8c7f3af17884473b133120e 100644 (file)
@@ -830,6 +830,8 @@ static ssize_t cache_do_downcall(char *kaddr, const char __user *buf,
 {
        ssize_t ret;
 
+       if (count == 0)
+               return -EINVAL;
        if (copy_from_user(kaddr, buf, count))
                return -EFAULT;
        kaddr[count] = '\0';
index bcd574f2ac566a96c34b041f44ce1e0b1bedbed8..521d8f7dc833ac769afe83daf0b03fe818c5be32 100644 (file)
@@ -507,7 +507,7 @@ static int unix_gid_parse(struct cache_detail *cd,
        time_t expiry;
        struct unix_gid ug, *ugp;
 
-       if (mlen <= 0 || mesg[mlen-1] != '\n')
+       if (mesg[mlen - 1] != '\n')
                return -EINVAL;
        mesg[mlen-1] = 0;
 
index 40ae884db865f975f589a433432652d0fe1936ed..824d32fb31214b5f433f439c439e7161fba28fb5 100644 (file)
@@ -1381,8 +1381,6 @@ void svc_sock_update_bufs(struct svc_serv *serv)
        spin_lock_bh(&serv->sv_lock);
        list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list)
                set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
-       list_for_each_entry(svsk, &serv->sv_tempsocks, sk_xprt.xpt_list)
-               set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
        spin_unlock_bh(&serv->sv_lock);
 }
 EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
index 09af4fab1a456c32c5c7b414ab8923cb29a8ef02..8343737e85f4d87136fd4adff6c0d4ba296e0c2c 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/svc_rdma.h>
+#include "xprt_rdma.h"
 
 #define RPCDBG_FACILITY        RPCDBG_SVCXPRT
 
index 9530ef2d40dc73c6c0849f761f399aff38121466..8d2edddf48cf13c6d283bd8784e61c7601f23fc7 100644 (file)
@@ -60,21 +60,11 @@ static u32 *decode_read_list(u32 *va, u32 *vaend)
        struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va;
 
        while (ch->rc_discrim != xdr_zero) {
-               u64 ch_offset;
-
                if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) >
                    (unsigned long)vaend) {
                        dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch);
                        return NULL;
                }
-
-               ch->rc_discrim = ntohl(ch->rc_discrim);
-               ch->rc_position = ntohl(ch->rc_position);
-               ch->rc_target.rs_handle = ntohl(ch->rc_target.rs_handle);
-               ch->rc_target.rs_length = ntohl(ch->rc_target.rs_length);
-               va = (u32 *)&ch->rc_target.rs_offset;
-               xdr_decode_hyper(va, &ch_offset);
-               put_unaligned(ch_offset, (u64 *)va);
                ch++;
        }
        return (u32 *)&ch->rc_position;
@@ -91,7 +81,7 @@ void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch,
        *byte_count = 0;
        *ch_count = 0;
        for (; ch->rc_discrim != 0; ch++) {
-               *byte_count = *byte_count + ch->rc_target.rs_length;
+               *byte_count = *byte_count + ntohl(ch->rc_target.rs_length);
                *ch_count = *ch_count + 1;
        }
 }
@@ -108,7 +98,8 @@ void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch,
  */
 static u32 *decode_write_list(u32 *va, u32 *vaend)
 {
-       int ch_no;
+       int nchunks;
+
        struct rpcrdma_write_array *ary =
                (struct rpcrdma_write_array *)va;
 
@@ -121,37 +112,24 @@ static u32 *decode_write_list(u32 *va, u32 *vaend)
                dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
                return NULL;
        }
-       ary->wc_discrim = ntohl(ary->wc_discrim);
-       ary->wc_nchunks = ntohl(ary->wc_nchunks);
+       nchunks = ntohl(ary->wc_nchunks);
        if (((unsigned long)&ary->wc_array[0] +
-            (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
+            (sizeof(struct rpcrdma_write_chunk) * nchunks)) >
            (unsigned long)vaend) {
                dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
-                       ary, ary->wc_nchunks, vaend);
+                       ary, nchunks, vaend);
                return NULL;
        }
-       for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
-               u64 ch_offset;
-
-               ary->wc_array[ch_no].wc_target.rs_handle =
-                       ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
-               ary->wc_array[ch_no].wc_target.rs_length =
-                       ntohl(ary->wc_array[ch_no].wc_target.rs_length);
-               va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
-               xdr_decode_hyper(va, &ch_offset);
-               put_unaligned(ch_offset, (u64 *)va);
-       }
-
        /*
         * rs_length is the 2nd 4B field in wc_target and taking its
         * address skips the list terminator
         */
-       return (u32 *)&ary->wc_array[ch_no].wc_target.rs_length;
+       return (u32 *)&ary->wc_array[nchunks].wc_target.rs_length;
 }
 
 static u32 *decode_reply_array(u32 *va, u32 *vaend)
 {
-       int ch_no;
+       int nchunks;
        struct rpcrdma_write_array *ary =
                (struct rpcrdma_write_array *)va;
 
@@ -164,28 +142,15 @@ static u32 *decode_reply_array(u32 *va, u32 *vaend)
                dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
                return NULL;
        }
-       ary->wc_discrim = ntohl(ary->wc_discrim);
-       ary->wc_nchunks = ntohl(ary->wc_nchunks);
+       nchunks = ntohl(ary->wc_nchunks);
        if (((unsigned long)&ary->wc_array[0] +
-            (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
+            (sizeof(struct rpcrdma_write_chunk) * nchunks)) >
            (unsigned long)vaend) {
                dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
-                       ary, ary->wc_nchunks, vaend);
+                       ary, nchunks, vaend);
                return NULL;
        }
-       for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
-               u64 ch_offset;
-
-               ary->wc_array[ch_no].wc_target.rs_handle =
-                       ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
-               ary->wc_array[ch_no].wc_target.rs_length =
-                       ntohl(ary->wc_array[ch_no].wc_target.rs_length);
-               va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
-               xdr_decode_hyper(va, &ch_offset);
-               put_unaligned(ch_offset, (u64 *)va);
-       }
-
-       return (u32 *)&ary->wc_array[ch_no];
+       return (u32 *)&ary->wc_array[nchunks];
 }
 
 int svc_rdma_xdr_decode_req(struct rpcrdma_msg **rdma_req,
@@ -386,13 +351,14 @@ void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *ary,
 
 void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *ary,
                                     int chunk_no,
-                                    u32 rs_handle, u64 rs_offset,
+                                    __be32 rs_handle,
+                                    __be64 rs_offset,
                                     u32 write_len)
 {
        struct rpcrdma_segment *seg = &ary->wc_array[chunk_no].wc_target;
-       seg->rs_handle = htonl(rs_handle);
+       seg->rs_handle = rs_handle;
+       seg->rs_offset = rs_offset;
        seg->rs_length = htonl(write_len);
-       xdr_encode_hyper((u32 *) &seg->rs_offset, rs_offset);
 }
 
 void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *xprt,
index df67211c4bafa34449d7449cf221e354884bd39d..41cb63b623dfa5033388740d454f937c84ae1db3 100644 (file)
@@ -147,7 +147,7 @@ static int map_read_chunks(struct svcxprt_rdma *xprt,
        page_off = 0;
        ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
        ch_no = 0;
-       ch_bytes = ch->rc_target.rs_length;
+       ch_bytes = ntohl(ch->rc_target.rs_length);
        head->arg.head[0] = rqstp->rq_arg.head[0];
        head->arg.tail[0] = rqstp->rq_arg.tail[0];
        head->arg.pages = &head->pages[head->count];
@@ -183,7 +183,7 @@ static int map_read_chunks(struct svcxprt_rdma *xprt,
                        ch_no++;
                        ch++;
                        chl_map->ch[ch_no].start = sge_no;
-                       ch_bytes = ch->rc_target.rs_length;
+                       ch_bytes = ntohl(ch->rc_target.rs_length);
                        /* If bytes remaining account for next chunk */
                        if (byte_count) {
                                head->arg.page_len += ch_bytes;
@@ -281,11 +281,12 @@ static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
        offset = 0;
        ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
        for (ch_no = 0; ch_no < ch_count; ch_no++) {
+               int len = ntohl(ch->rc_target.rs_length);
                rpl_map->sge[ch_no].iov_base = frmr->kva + offset;
-               rpl_map->sge[ch_no].iov_len = ch->rc_target.rs_length;
+               rpl_map->sge[ch_no].iov_len = len;
                chl_map->ch[ch_no].count = 1;
                chl_map->ch[ch_no].start = ch_no;
-               offset += ch->rc_target.rs_length;
+               offset += len;
                ch++;
        }
 
@@ -316,7 +317,7 @@ static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
        for (i = 0; i < count; i++) {
                ctxt->sge[i].length = 0; /* in case map fails */
                if (!frmr) {
-                       BUG_ON(0 == virt_to_page(vec[i].iov_base));
+                       BUG_ON(!virt_to_page(vec[i].iov_base));
                        off = (unsigned long)vec[i].iov_base & ~PAGE_MASK;
                        ctxt->sge[i].addr =
                                ib_dma_map_page(xprt->sc_cm_id->device,
@@ -426,6 +427,7 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
 
        for (ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
             ch->rc_discrim != 0; ch++, ch_no++) {
+               u64 rs_offset;
 next_sge:
                ctxt = svc_rdma_get_context(xprt);
                ctxt->direction = DMA_FROM_DEVICE;
@@ -440,10 +442,10 @@ next_sge:
                read_wr.opcode = IB_WR_RDMA_READ;
                ctxt->wr_op = read_wr.opcode;
                read_wr.send_flags = IB_SEND_SIGNALED;
-               read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
-               read_wr.wr.rdma.remote_addr =
-                       get_unaligned(&(ch->rc_target.rs_offset)) +
-                       sgl_offset;
+               read_wr.wr.rdma.rkey = ntohl(ch->rc_target.rs_handle);
+               xdr_decode_hyper((__be32 *)&ch->rc_target.rs_offset,
+                                &rs_offset);
+               read_wr.wr.rdma.remote_addr = rs_offset + sgl_offset;
                read_wr.sg_list = ctxt->sge;
                read_wr.num_sge =
                        rdma_read_max_sge(xprt, chl_map->ch[ch_no].count);
index 249a835b703f1f0ec46c6051ff98249227876509..42eb7ba0b9034afc1ade6770fea5d49fe305cc97 100644 (file)
@@ -409,21 +409,21 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
                u64 rs_offset;
 
                arg_ch = &arg_ary->wc_array[chunk_no].wc_target;
-               write_len = min(xfer_len, arg_ch->rs_length);
+               write_len = min(xfer_len, ntohl(arg_ch->rs_length));
 
                /* Prepare the response chunk given the length actually
                 * written */
-               rs_offset = get_unaligned(&(arg_ch->rs_offset));
+               xdr_decode_hyper((__be32 *)&arg_ch->rs_offset, &rs_offset);
                svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
-                                           arg_ch->rs_handle,
-                                           rs_offset,
-                                           write_len);
+                                               arg_ch->rs_handle,
+                                               arg_ch->rs_offset,
+                                               write_len);
                chunk_off = 0;
                while (write_len) {
                        int this_write;
                        this_write = min(write_len, max_write);
                        ret = send_write(xprt, rqstp,
-                                        arg_ch->rs_handle,
+                                        ntohl(arg_ch->rs_handle),
                                         rs_offset + chunk_off,
                                         xdr_off,
                                         this_write,
@@ -457,6 +457,7 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
        u32 xdr_off;
        int chunk_no;
        int chunk_off;
+       int nchunks;
        struct rpcrdma_segment *ch;
        struct rpcrdma_write_array *arg_ary;
        struct rpcrdma_write_array *res_ary;
@@ -476,26 +477,27 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
                max_write = xprt->sc_max_sge * PAGE_SIZE;
 
        /* xdr offset starts at RPC message */
+       nchunks = ntohl(arg_ary->wc_nchunks);
        for (xdr_off = 0, chunk_no = 0;
-            xfer_len && chunk_no < arg_ary->wc_nchunks;
+            xfer_len && chunk_no < nchunks;
             chunk_no++) {
                u64 rs_offset;
                ch = &arg_ary->wc_array[chunk_no].wc_target;
-               write_len = min(xfer_len, ch->rs_length);
+               write_len = min(xfer_len, htonl(ch->rs_length));
 
                /* Prepare the reply chunk given the length actually
                 * written */
-               rs_offset = get_unaligned(&(ch->rs_offset));
+               xdr_decode_hyper((__be32 *)&ch->rs_offset, &rs_offset);
                svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
-                                           ch->rs_handle, rs_offset,
-                                           write_len);
+                                               ch->rs_handle, ch->rs_offset,
+                                               write_len);
                chunk_off = 0;
                while (write_len) {
                        int this_write;
 
                        this_write = min(write_len, max_write);
                        ret = send_write(xprt, rqstp,
-                                        ch->rs_handle,
+                                        ntohl(ch->rs_handle),
                                         rs_offset + chunk_off,
                                         xdr_off,
                                         this_write,
index 894cb42db91d6c9e2cb71a9ae0aa076db4573d96..73b428bef5986bd06b751bf45b3f3f7f6698fdd2 100644 (file)
@@ -51,6 +51,7 @@
 #include <rdma/rdma_cm.h>
 #include <linux/sunrpc/svc_rdma.h>
 #include <linux/export.h>
+#include "xprt_rdma.h"
 
 #define RPCDBG_FACILITY        RPCDBG_SVCXPRT
 
@@ -90,12 +91,6 @@ struct svc_xprt_class svc_rdma_class = {
        .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
 };
 
-/* WR context cache. Created in svc_rdma.c  */
-extern struct kmem_cache *svc_rdma_ctxt_cachep;
-
-/* Workqueue created in svc_rdma.c */
-extern struct workqueue_struct *svc_rdma_wq;
-
 struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
 {
        struct svc_rdma_op_ctxt *ctxt;
@@ -150,9 +145,6 @@ void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
        atomic_dec(&xprt->sc_ctxt_used);
 }
 
-/* Temporary NFS request map cache. Created in svc_rdma.c  */
-extern struct kmem_cache *svc_rdma_map_cachep;
-
 /*
  * Temporary NFS req mappings are shared across all transport
  * instances. These are short lived and should be bounded by the number
index 08c5d5a128fc44e835a6f6ac13f6b81a5387c889..9a66c95b5837159b8f3758795a48009bb6f8108a 100644 (file)
@@ -343,4 +343,11 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *);
  */
 int rpcrdma_marshal_req(struct rpc_rqst *);
 
+/* Temporary NFS request map cache. Created in svc_rdma.c  */
+extern struct kmem_cache *svc_rdma_map_cachep;
+/* WR context cache. Created in svc_rdma.c  */
+extern struct kmem_cache *svc_rdma_ctxt_cachep;
+/* Workqueue created in svc_rdma.c */
+extern struct workqueue_struct *svc_rdma_wq;
+
 #endif                         /* _LINUX_SUNRPC_XPRT_RDMA_H */