]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Sat, 5 May 2007 02:55:11 +0000 (19:55 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Sat, 5 May 2007 02:55:11 +0000 (19:55 -0700)
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (28 commits)
  NFS: Fix a compile glitch on 64-bit systems
  NFS: Clean up nfs_create_request comments
  spkm3: initialize hash
  spkm3: remove bad kfree, unnecessary export
  spkm3: fix spkm3's use of hmac
  NFS4: invalidate cached acl on setacl
  NFS: Fix directory caching problem - with test case and patch.
  NFS: Set meaningful value for fattr->time_start in readdirplus results.
  NFS: Added support to turn off the NFSv3 READDIRPLUS RPC.
  SUNRPC: RPC client should retry with different versions of rpcbind
  SUNRPC: remove old portmapper
  NFS: switch NFSROOT to use new rpcbind client
  SUNRPC: switch the RPC server to use the new rpcbind registration API
  SUNRPC: switch socket-based RPC transports to use rpcbind
  SUNRPC: introduce rpcbind: replacement for in-kernel portmapper
  SUNRPC: Eliminate side effects from rpc_malloc
  SUNRPC: RPC buffer size estimates are too large
  NLM: Shrink the maximum request size of NLM4 requests
  NFS: Use pgoff_t in structures and functions that pass page cache offsets
  NFS: Clean up nfs_sync_mapping_wait()
  ...

38 files changed:
fs/Kconfig
fs/lockd/mon.c
fs/lockd/xdr.c
fs/lockd/xdr4.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/internal.h
fs/nfs/mount_clnt.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
fs/nfs/nfsroot.c
fs/nfs/pagelist.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/nfs4callback.c
include/linux/lockd/lockd.h
include/linux/nfs_fs.h
include/linux/nfs_mount.h
include/linux/nfs_page.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/debug.h
include/linux/sunrpc/msg_prot.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/xprt.h
include/linux/writeback.h
net/sunrpc/Makefile
net/sunrpc/auth_gss/gss_spkm3_seal.c
net/sunrpc/clnt.c
net/sunrpc/pmap_clnt.c [deleted file]
net/sunrpc/rpcb_clnt.c [new file with mode: 0644]
net/sunrpc/sched.c
net/sunrpc/svc.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c

index e33c089245721cd6d9e0dd797ec786187add7135..8ea7b04c661ff5360af30e399ea5a993889298d4 100644 (file)
@@ -1734,6 +1734,18 @@ config SUNRPC
 config SUNRPC_GSS
        tristate
 
+config SUNRPC_BIND34
+       bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
+       depends on SUNRPC && EXPERIMENTAL
+       help
+         Provides kernel support for querying rpcbind servers via versions 3
+         and 4 of the rpcbind protocol.  The kernel automatically falls back
+         to version 2 if a remote rpcbind service does not support versions
+         3 or 4.
+
+         If unsure, say N to get traditional behavior (version 2 rpcbind
+         requests only).
+
 config RPCSEC_GSS_KRB5
        tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
        depends on SUNRPC && EXPERIMENTAL
index eb243edf8932b36e58c26f72c24efeb46f1040b3..2102e2d0134dc2db7c9a50da58a29f35aea34711 100644 (file)
@@ -225,16 +225,13 @@ xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
 #define SM_monres_sz   2
 #define SM_unmonres_sz 1
 
-#ifndef MAX
-# define MAX(a, b)     (((a) > (b))? (a) : (b))
-#endif
-
 static struct rpc_procinfo     nsm_procedures[] = {
 [SM_MON] = {
                .p_proc         = SM_MON,
                .p_encode       = (kxdrproc_t) xdr_encode_mon,
                .p_decode       = (kxdrproc_t) xdr_decode_stat_res,
-               .p_bufsiz       = MAX(SM_mon_sz, SM_monres_sz) << 2,
+               .p_arglen       = SM_mon_sz,
+               .p_replen       = SM_monres_sz,
                .p_statidx      = SM_MON,
                .p_name         = "MONITOR",
        },
@@ -242,7 +239,8 @@ static struct rpc_procinfo  nsm_procedures[] = {
                .p_proc         = SM_UNMON,
                .p_encode       = (kxdrproc_t) xdr_encode_unmon,
                .p_decode       = (kxdrproc_t) xdr_decode_stat,
-               .p_bufsiz       = MAX(SM_mon_id_sz, SM_unmonres_sz) << 2,
+               .p_arglen       = SM_mon_id_sz,
+               .p_replen       = SM_unmonres_sz,
                .p_statidx      = SM_UNMON,
                .p_name         = "UNMONITOR",
        },
index 34dae5d70738bff79bc78945fd647dc4f16bdbca..9702956d206cf69ce9c4d5c6b3d419f0144359e8 100644 (file)
@@ -510,17 +510,20 @@ nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
        return 0;
 }
 
+#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
+#  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
+#endif
+
 /*
  * Buffer requirements for NLM
  */
 #define NLM_void_sz            0
 #define NLM_cookie_sz          1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
-#define NLM_caller_sz          1+XDR_QUADLEN(sizeof(utsname()->nodename))
-#define NLM_netobj_sz          1+XDR_QUADLEN(XDR_MAX_NETOBJ)
-/* #define NLM_owner_sz                1+XDR_QUADLEN(NLM_MAXOWNER) */
+#define NLM_caller_sz          1+XDR_QUADLEN(NLMCLNT_OHSIZE)
+#define NLM_owner_sz           1+XDR_QUADLEN(NLMCLNT_OHSIZE)
 #define NLM_fhandle_sz         1+XDR_QUADLEN(NFS2_FHSIZE)
-#define NLM_lock_sz            3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz
-#define NLM_holder_sz          4+NLM_netobj_sz
+#define NLM_lock_sz            3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz
+#define NLM_holder_sz          4+NLM_owner_sz
 
 #define NLM_testargs_sz                NLM_cookie_sz+1+NLM_lock_sz
 #define NLM_lockargs_sz                NLM_cookie_sz+4+NLM_lock_sz
@@ -531,10 +534,6 @@ nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 #define NLM_res_sz             NLM_cookie_sz+1
 #define NLM_norep_sz           0
 
-#ifndef MAX
-# define MAX(a, b)             (((a) > (b))? (a) : (b))
-#endif
-
 /*
  * For NLM, a void procedure really returns nothing
  */
@@ -545,7 +544,8 @@ nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
        .p_proc      = NLMPROC_##proc,                                  \
        .p_encode    = (kxdrproc_t) nlmclt_encode_##argtype,            \
        .p_decode    = (kxdrproc_t) nlmclt_decode_##restype,            \
-       .p_bufsiz    = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2,        \
+       .p_arglen    = NLM_##argtype##_sz,                              \
+       .p_replen    = NLM_##restype##_sz,                              \
        .p_statidx   = NLMPROC_##proc,                                  \
        .p_name      = #proc,                                           \
        }
index a78240551219a91ba8d5a34eff83ed8002331bb6..ce1efdbe1b3a49616a8698c49efc75b6c2deba2c 100644 (file)
@@ -516,17 +516,24 @@ nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
        return 0;
 }
 
+#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
+#  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
+#endif
+
+#if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN)
+#  error "NLM host name cannot be larger than NLM's maximum string length!"
+#endif
+
 /*
  * Buffer requirements for NLM
  */
 #define NLM4_void_sz           0
 #define NLM4_cookie_sz         1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
-#define NLM4_caller_sz         1+XDR_QUADLEN(NLM_MAXSTRLEN)
-#define NLM4_netobj_sz         1+XDR_QUADLEN(XDR_MAX_NETOBJ)
-/* #define NLM4_owner_sz               1+XDR_QUADLEN(NLM4_MAXOWNER) */
+#define NLM4_caller_sz         1+XDR_QUADLEN(NLMCLNT_OHSIZE)
+#define NLM4_owner_sz          1+XDR_QUADLEN(NLMCLNT_OHSIZE)
 #define NLM4_fhandle_sz                1+XDR_QUADLEN(NFS3_FHSIZE)
-#define NLM4_lock_sz           5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
-#define NLM4_holder_sz         6+NLM4_netobj_sz
+#define NLM4_lock_sz           5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz
+#define NLM4_holder_sz         6+NLM4_owner_sz
 
 #define NLM4_testargs_sz       NLM4_cookie_sz+1+NLM4_lock_sz
 #define NLM4_lockargs_sz       NLM4_cookie_sz+4+NLM4_lock_sz
@@ -537,10 +544,6 @@ nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 #define NLM4_res_sz            NLM4_cookie_sz+1
 #define NLM4_norep_sz          0
 
-#ifndef MAX
-# define MAX(a,b)              (((a) > (b))? (a) : (b))
-#endif
-
 /*
  * For NLM, a void procedure really returns nothing
  */
@@ -551,7 +554,8 @@ nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
        .p_proc      = NLMPROC_##proc,                                  \
        .p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,           \
        .p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,           \
-       .p_bufsiz    = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2,      \
+       .p_arglen    = NLM4_##argtype##_sz,                             \
+       .p_replen    = NLM4_##restype##_sz,                             \
        .p_statidx   = NLMPROC_##proc,                                  \
        .p_name      = #proc,                                           \
        }
index 2190e6c2792e6f7ed1383f49b1e2f96c6565ef3d..5bd03b97002e1e9dd73f1d36aeecaaf76c94da5c 100644 (file)
@@ -618,7 +618,8 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat
        if (clp->cl_nfsversion == 3) {
                if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
                        server->namelen = NFS3_MAXNAMLEN;
-               server->caps |= NFS_CAP_READDIRPLUS;
+               if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
+                       server->caps |= NFS_CAP_READDIRPLUS;
        } else {
                if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
                        server->namelen = NFS2_MAXNAMLEN;
index cd3469720cbf9e08e07ac085f98255e2d7ade549..e59fd31c9a22abfdd052249b4cbaa52e04147cfd 100644 (file)
@@ -154,6 +154,8 @@ typedef struct {
        decode_dirent_t decode;
        int             plus;
        int             error;
+       unsigned long   timestamp;
+       int             timestamp_valid;
 } nfs_readdir_descriptor_t;
 
 /* Now we cache directories properly, by stuffing the dirent
@@ -195,6 +197,8 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
                }
                goto error;
        }
+       desc->timestamp = timestamp;
+       desc->timestamp_valid = 1;
        SetPageUptodate(page);
        spin_lock(&inode->i_lock);
        NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
@@ -225,6 +229,10 @@ int dir_decode(nfs_readdir_descriptor_t *desc)
        if (IS_ERR(p))
                return PTR_ERR(p);
        desc->ptr = p;
+       if (desc->timestamp_valid)
+               desc->entry->fattr->time_start = desc->timestamp;
+       else
+               desc->entry->fattr->valid &= ~NFS_ATTR_FATTR;
        return 0;
 }
 
@@ -316,6 +324,10 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
                        __FUNCTION__, desc->page_index,
                        (long long) *desc->dir_cookie);
 
+       /* If we find the page in the page_cache, we cannot be sure
+        * how fresh the data is, so we will ignore readdir_plus attributes.
+        */
+       desc->timestamp_valid = 0;
        page = read_cache_page(inode->i_mapping, desc->page_index,
                               (filler_t *)nfs_readdir_filler, desc);
        if (IS_ERR(page)) {
@@ -468,6 +480,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        struct rpc_cred *cred = nfs_file_cred(file);
        struct page     *page = NULL;
        int             status;
+       unsigned long   timestamp;
 
        dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
                        (unsigned long long)*desc->dir_cookie);
@@ -477,6 +490,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
                status = -ENOMEM;
                goto out;
        }
+       timestamp = jiffies;
        desc->error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, *desc->dir_cookie,
                                                page,
                                                NFS_SERVER(inode)->dtsize,
@@ -487,6 +501,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        desc->page = page;
        desc->ptr = kmap(page);         /* matching kunmap in nfs_do_filldir */
        if (desc->error >= 0) {
+               desc->timestamp = timestamp;
+               desc->timestamp_valid = 1;
                if ((status = dir_decode(desc)) == 0)
                        desc->entry->prev_cookie = *desc->dir_cookie;
        } else
@@ -849,6 +865,10 @@ static int nfs_dentry_delete(struct dentry *dentry)
 static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
 {
        nfs_inode_return_delegation(inode);
+       if (S_ISDIR(inode->i_mode))
+               /* drop any readdir cache as it could easily be old */
+               NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
+
        if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
                lock_kernel();
                drop_nlink(inode);
index 2877744cb6069439ec60e199d715eb55276fb6fc..889de60f8a842bdadc771a32fc3a192ca23873e2 100644 (file)
@@ -54,6 +54,7 @@
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
 
+#include "internal.h"
 #include "iostat.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
@@ -271,7 +272,7 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
                bytes = min(rsize,count);
 
                result = -ENOMEM;
-               data = nfs_readdata_alloc(pgbase + bytes);
+               data = nfs_readdata_alloc(nfs_page_array_len(pgbase, bytes));
                if (unlikely(!data))
                        break;
 
@@ -602,7 +603,7 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
                bytes = min(wsize,count);
 
                result = -ENOMEM;
-               data = nfs_writedata_alloc(pgbase + bytes);
+               data = nfs_writedata_alloc(nfs_page_array_len(pgbase, bytes));
                if (unlikely(!data))
                        break;
 
index 6610f2b0207743a26693a43db49b63b0d8c058b2..ad2b40db1e65f901d7081c27ed0b9650816a8f6d 100644 (file)
@@ -231,3 +231,15 @@ unsigned int nfs_page_length(struct page *page)
        }
        return 0;
 }
+
+/*
+ * Determine the number of pages in an array of length 'len' and
+ * with a base offset of 'base'
+ */
+static inline
+unsigned int nfs_page_array_len(unsigned int base, size_t len)
+{
+       return ((unsigned long)len + (unsigned long)base +
+               PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
index f75fe72b4160b7bdfbae6631d87c3bca8e63d496..ca5a266a3140430266e7c57a2292134218cad6c1 100644 (file)
@@ -133,13 +133,15 @@ xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
 
 #define MNT_dirpath_sz         (1 + 256)
 #define MNT_fhstatus_sz                (1 + 8)
+#define MNT_fhstatus3_sz       (1 + 16)
 
 static struct rpc_procinfo     mnt_procedures[] = {
 [MNTPROC_MNT] = {
          .p_proc               = MNTPROC_MNT,
          .p_encode             = (kxdrproc_t) xdr_encode_dirpath,      
          .p_decode             = (kxdrproc_t) xdr_decode_fhstatus,
-         .p_bufsiz             = MNT_dirpath_sz << 2,
+         .p_arglen             = MNT_dirpath_sz,
+         .p_replen             = MNT_fhstatus_sz,
          .p_statidx            = MNTPROC_MNT,
          .p_name               = "MOUNT",
        },
@@ -150,7 +152,8 @@ static struct rpc_procinfo mnt3_procedures[] = {
          .p_proc               = MOUNTPROC3_MNT,
          .p_encode             = (kxdrproc_t) xdr_encode_dirpath,
          .p_decode             = (kxdrproc_t) xdr_decode_fhstatus3,
-         .p_bufsiz             = MNT_dirpath_sz << 2,
+         .p_arglen             = MNT_dirpath_sz,
+         .p_replen             = MNT_fhstatus3_sz,
          .p_statidx            = MOUNTPROC3_MNT,
          .p_name               = "MOUNT",
        },
index 3be4e72a0227e71030709b019dd35db28897a34e..abd9f8b48943997f5b30a4b500da26955013e863 100644 (file)
@@ -687,16 +687,13 @@ nfs_stat_to_errno(int stat)
        return nfs_errtbl[i].errno;
 }
 
-#ifndef MAX
-# define MAX(a, b)     (((a) > (b))? (a) : (b))
-#endif
-
 #define PROC(proc, argtype, restype, timer)                            \
 [NFSPROC_##proc] = {                                                   \
        .p_proc     =  NFSPROC_##proc,                                  \
        .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,                  \
        .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,                  \
-       .p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
+       .p_arglen   =  NFS_##argtype##_sz,                              \
+       .p_replen   =  NFS_##restype##_sz,                              \
        .p_timer    =  timer,                                           \
        .p_statidx  =  NFSPROC_##proc,                                  \
        .p_name     =  #proc,                                           \
index 0ace092d126f930e10e946340c8c04b8be7dfa14..b51df8eb9f010c070ec4545248374fa02687e175 100644 (file)
@@ -1102,16 +1102,13 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 }
 #endif  /* CONFIG_NFS_V3_ACL */
 
-#ifndef MAX
-# define MAX(a, b)     (((a) > (b))? (a) : (b))
-#endif
-
 #define PROC(proc, argtype, restype, timer)                            \
 [NFS3PROC_##proc] = {                                                  \
        .p_proc      = NFS3PROC_##proc,                                 \
        .p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,                 \
        .p_decode    = (kxdrproc_t) nfs3_xdr_##restype,                 \
-       .p_bufsiz    = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,       \
+       .p_arglen    = NFS3_##argtype##_sz,                             \
+       .p_replen    = NFS3_##restype##_sz,                             \
        .p_timer     = timer,                                           \
        .p_statidx   = NFS3PROC_##proc,                                 \
        .p_name      = #proc,                                           \
@@ -1153,7 +1150,8 @@ static struct rpc_procinfo        nfs3_acl_procedures[] = {
                .p_proc = ACLPROC3_GETACL,
                .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
                .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
-               .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
+               .p_arglen = ACL3_getaclargs_sz,
+               .p_replen = ACL3_getaclres_sz,
                .p_timer = 1,
                .p_name = "GETACL",
        },
@@ -1161,7 +1159,8 @@ static struct rpc_procinfo        nfs3_acl_procedures[] = {
                .p_proc = ACLPROC3_SETACL,
                .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
                .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
-               .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
+               .p_arglen = ACL3_setaclargs_sz,
+               .p_replen = ACL3_setaclres_sz,
                .p_timer = 0,
                .p_name = "SETACL",
        },
index f52cf5c33c6c83adcde94ed37202adaf3a0d969f..3b5ca1b15fe9eb69b5b6b872d85eea18620d8e7f 100644 (file)
@@ -2647,8 +2647,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
        nfs_inode_return_delegation(inode);
        buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
        ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
-       if (ret == 0)
-               nfs4_write_cached_acl(inode, buf, buflen);
+       nfs_zap_caches(inode);
        return ret;
 }
 
index f02d522fd78862a5195c5f461d8546cbe24863bf..b8c28f2380a5bcf2aacb48cb45294df65379d21d 100644 (file)
@@ -4546,16 +4546,13 @@ nfs4_stat_to_errno(int stat)
        return stat;
 }
 
-#ifndef MAX
-# define MAX(a, b)     (((a) > (b))? (a) : (b))
-#endif
-
 #define PROC(proc, argtype, restype)                           \
 [NFSPROC4_CLNT_##proc] = {                                     \
        .p_proc   = NFSPROC4_COMPOUND,                          \
        .p_encode = (kxdrproc_t) nfs4_xdr_##argtype,            \
        .p_decode = (kxdrproc_t) nfs4_xdr_##restype,            \
-       .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2,  \
+       .p_arglen = NFS4_##argtype##_sz,                        \
+       .p_replen = NFS4_##restype##_sz,                        \
        .p_statidx = NFSPROC4_CLNT_##proc,                      \
        .p_name   = #proc,                                      \
     }
index 75f819dc025575dda5426aca05f6f128e20f3dba..49d1008ce1d702c8307249f4a1e1e94d389e72b0 100644 (file)
@@ -428,7 +428,7 @@ static int __init root_nfs_getport(int program, int version, int proto)
        printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n",
                program, version, NIPQUAD(servaddr));
        set_sockaddr(&sin, servaddr, 0);
-       return rpc_getport_external(&sin, program, version, proto);
+       return rpcb_getport_external(&sin, program, version, proto);
 }
 
 
index ca4b1d4ff42b0f7d337ad01fa7c1675f959c4134..388950118f59ae5b30c90b64dfc5d618aa7fd33f 100644 (file)
@@ -17,7 +17,8 @@
 #include <linux/nfs_page.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
-#include <linux/writeback.h>
+
+#include "internal.h"
 
 #define NFS_PARANOIA 1
 
@@ -50,9 +51,7 @@ nfs_page_free(struct nfs_page *p)
  * @count: number of bytes to read/write
  *
  * The page must be locked by the caller. This makes sure we never
- * create two different requests for the same page, and avoids
- * a possible deadlock when we reach the hard limit on the number
- * of dirty pages.
+ * create two different requests for the same page.
  * User should ensure it is safe to sleep in this function.
  */
 struct nfs_page *
@@ -63,16 +62,12 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs_page         *req;
 
-       /* Deal with hard limits.  */
        for (;;) {
                /* try to allocate the request struct */
                req = nfs_page_alloc();
                if (req != NULL)
                        break;
 
-               /* Try to free up at least one request in order to stay
-                * below the hard limit
-                */
                if (signalled() && (server->flags & NFS_MOUNT_INTR))
                        return ERR_PTR(-ERESTARTSYS);
                yield();
@@ -223,123 +218,150 @@ out:
 }
 
 /**
- * nfs_coalesce_requests - Split coalesced requests out from a list.
- * @head: source list
- * @dst: destination list
- * @nmax: maximum number of requests to coalesce
- *
- * Moves a maximum of 'nmax' elements from one list to another.
- * The elements are checked to ensure that they form a contiguous set
- * of pages, and that the RPC credentials are the same.
+ * nfs_pageio_init - initialise a page io descriptor
+ * @desc: pointer to descriptor
+ * @inode: pointer to inode
+ * @doio: pointer to io function
+ * @bsize: io block size
+ * @io_flags: extra parameters for the io function
  */
-int
-nfs_coalesce_requests(struct list_head *head, struct list_head *dst,
-                     unsigned int nmax)
+void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
+                    struct inode *inode,
+                    int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+                    size_t bsize,
+                    int io_flags)
 {
-       struct nfs_page         *req = NULL;
-       unsigned int            npages = 0;
-
-       while (!list_empty(head)) {
-               struct nfs_page *prev = req;
-
-               req = nfs_list_entry(head->next);
-               if (prev) {
-                       if (req->wb_context->cred != prev->wb_context->cred)
-                               break;
-                       if (req->wb_context->lockowner != prev->wb_context->lockowner)
-                               break;
-                       if (req->wb_context->state != prev->wb_context->state)
-                               break;
-                       if (req->wb_index != (prev->wb_index + 1))
-                               break;
-
-                       if (req->wb_pgbase != 0)
-                               break;
-               }
-               nfs_list_remove_request(req);
-               nfs_list_add_request(req, dst);
-               npages++;
-               if (req->wb_pgbase + req->wb_bytes != PAGE_CACHE_SIZE)
-                       break;
-               if (npages >= nmax)
-                       break;
-       }
-       return npages;
+       INIT_LIST_HEAD(&desc->pg_list);
+       desc->pg_bytes_written = 0;
+       desc->pg_count = 0;
+       desc->pg_bsize = bsize;
+       desc->pg_base = 0;
+       desc->pg_inode = inode;
+       desc->pg_doio = doio;
+       desc->pg_ioflags = io_flags;
+       desc->pg_error = 0;
 }
 
-#define NFS_SCAN_MAXENTRIES 16
 /**
- * nfs_scan_dirty - Scan the radix tree for dirty requests
- * @mapping: pointer to address space
- * @wbc: writeback_control structure
- * @dst: Destination list
+ * nfs_can_coalesce_requests - test two requests for compatibility
+ * @prev: pointer to nfs_page
+ * @req: pointer to nfs_page
  *
- * Moves elements from one of the inode request lists.
- * If the number of requests is set to 0, the entire address_space
- * starting at index idx_start, is scanned.
- * The requests are *not* checked to ensure that they form a contiguous set.
- * You must be holding the inode's req_lock when calling this function
+ * The nfs_page structures 'prev' and 'req' are compared to ensure that the
+ * page data area they describe is contiguous, and that their RPC
+ * credentials, NFSv4 open state, and lockowners are the same.
+ *
+ * Return 'true' if this is the case, else return 'false'.
  */
-long nfs_scan_dirty(struct address_space *mapping,
-                       struct writeback_control *wbc,
-                       struct list_head *dst)
+static int nfs_can_coalesce_requests(struct nfs_page *prev,
+                                    struct nfs_page *req)
 {
-       struct nfs_inode *nfsi = NFS_I(mapping->host);
-       struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
-       struct nfs_page *req;
-       pgoff_t idx_start, idx_end;
-       long res = 0;
-       int found, i;
-
-       if (nfsi->ndirty == 0)
+       if (req->wb_context->cred != prev->wb_context->cred)
                return 0;
-       if (wbc->range_cyclic) {
-               idx_start = 0;
-               idx_end = ULONG_MAX;
-       } else if (wbc->range_end == 0) {
-               idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
-               idx_end = ULONG_MAX;
-       } else {
-               idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
-               idx_end = wbc->range_end >> PAGE_CACHE_SHIFT;
-       }
+       if (req->wb_context->lockowner != prev->wb_context->lockowner)
+               return 0;
+       if (req->wb_context->state != prev->wb_context->state)
+               return 0;
+       if (req->wb_index != (prev->wb_index + 1))
+               return 0;
+       if (req->wb_pgbase != 0)
+               return 0;
+       if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
+               return 0;
+       return 1;
+}
 
-       for (;;) {
-               unsigned int toscan = NFS_SCAN_MAXENTRIES;
+/**
+ * nfs_pageio_do_add_request - Attempt to coalesce a request into a page list.
+ * @desc: destination io descriptor
+ * @req: request
+ *
+ * Returns true if the request 'req' was successfully coalesced into the
+ * existing list of pages 'desc'.
+ */
+static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
+                                    struct nfs_page *req)
+{
+       size_t newlen = req->wb_bytes;
 
-               found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,
-                               (void **)&pgvec[0], idx_start, toscan,
-                               NFS_PAGE_TAG_DIRTY);
+       if (desc->pg_count != 0) {
+               struct nfs_page *prev;
 
-               /* Did we make progress? */
-               if (found <= 0)
-                       break;
+               /*
+                * FIXME: ideally we should be able to coalesce all requests
+                * that are not block boundary aligned, but currently this
+                * is problematic for the case of bsize < PAGE_CACHE_SIZE,
+                * since nfs_flush_multi and nfs_pagein_multi assume you
+                * can have only one struct nfs_page.
+                */
+               if (desc->pg_bsize < PAGE_SIZE)
+                       return 0;
+               newlen += desc->pg_count;
+               if (newlen > desc->pg_bsize)
+                       return 0;
+               prev = nfs_list_entry(desc->pg_list.prev);
+               if (!nfs_can_coalesce_requests(prev, req))
+                       return 0;
+       } else
+               desc->pg_base = req->wb_pgbase;
+       nfs_list_remove_request(req);
+       nfs_list_add_request(req, &desc->pg_list);
+       desc->pg_count = newlen;
+       return 1;
+}
 
-               for (i = 0; i < found; i++) {
-                       req = pgvec[i];
-                       if (!wbc->range_cyclic && req->wb_index > idx_end)
-                               goto out;
+/*
+ * Helper for nfs_pageio_add_request and nfs_pageio_complete
+ */
+static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
+{
+       if (!list_empty(&desc->pg_list)) {
+               int error = desc->pg_doio(desc->pg_inode,
+                                         &desc->pg_list,
+                                         nfs_page_array_len(desc->pg_base,
+                                                            desc->pg_count),
+                                         desc->pg_count,
+                                         desc->pg_ioflags);
+               if (error < 0)
+                       desc->pg_error = error;
+               else
+                       desc->pg_bytes_written += desc->pg_count;
+       }
+       if (list_empty(&desc->pg_list)) {
+               desc->pg_count = 0;
+               desc->pg_base = 0;
+       }
+}
 
-                       /* Try to lock request and mark it for writeback */
-                       if (!nfs_set_page_writeback_locked(req))
-                               goto next;
-                       radix_tree_tag_clear(&nfsi->nfs_page_tree,
-                                       req->wb_index, NFS_PAGE_TAG_DIRTY);
-                       nfsi->ndirty--;
-                       nfs_list_remove_request(req);
-                       nfs_list_add_request(req, dst);
-                       res++;
-                       if (res == LONG_MAX)
-                               goto out;
-next:
-                       idx_start = req->wb_index + 1;
-               }
+/**
+ * nfs_pageio_add_request - Attempt to coalesce a request into a page list.
+ * @desc: destination io descriptor
+ * @req: request
+ *
+ * Returns true if the request 'req' was successfully coalesced into the
+ * existing list of pages 'desc'.
+ */
+int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
+                          struct nfs_page *req)
+{
+       while (!nfs_pageio_do_add_request(desc, req)) {
+               nfs_pageio_doio(desc);
+               if (desc->pg_error < 0)
+                       return 0;
        }
-out:
-       WARN_ON ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty));
-       return res;
+       return 1;
 }
 
+/**
+ * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor
+ * @desc: pointer to io descriptor
+ */
+void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
+{
+       nfs_pageio_doio(desc);
+}
+
+#define NFS_SCAN_MAXENTRIES 16
 /**
  * nfs_scan_list - Scan a list for matching requests
  * @nfsi: NFS inode
@@ -355,12 +377,12 @@ out:
  * You must be holding the inode's req_lock when calling this function
  */
 int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
-               struct list_head *dst, unsigned long idx_start,
+               struct list_head *dst, pgoff_t idx_start,
                unsigned int npages)
 {
        struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
        struct nfs_page *req;
-       unsigned long idx_end;
+       pgoff_t idx_end;
        int found, i;
        int res;
 
index 6ab4d5a9edf2e70f633b23e14b8e7b3c65716875..9a55807b2a701f6b33cee3bf195140e8b724f314 100644 (file)
@@ -27,7 +27,8 @@
 
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
-static int nfs_pagein_one(struct list_head *, struct inode *);
+static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int);
+static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int);
 static const struct rpc_call_ops nfs_read_partial_ops;
 static const struct rpc_call_ops nfs_read_full_ops;
 
@@ -36,9 +37,8 @@ static mempool_t *nfs_rdata_mempool;
 
 #define MIN_POOL_READ  (32)
 
-struct nfs_read_data *nfs_readdata_alloc(size_t len)
+struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
 {
-       unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS);
 
        if (p) {
@@ -133,7 +133,10 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
                memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
 
        nfs_list_add_request(new, &one_request);
-       nfs_pagein_one(&one_request, inode);
+       if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
+               nfs_pagein_multi(inode, &one_request, 1, len, 0);
+       else
+               nfs_pagein_one(inode, &one_request, 1, len, 0);
        return 0;
 }
 
@@ -230,7 +233,7 @@ static void nfs_execute_read(struct nfs_read_data *data)
  * won't see the new data until our attribute cache is updated.  This is more
  * or less conventional NFS client behavior.
  */
-static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
+static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
 {
        struct nfs_page *req = nfs_list_entry(head->next);
        struct page *page = req->wb_page;
@@ -242,11 +245,11 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
 
        nfs_list_remove_request(req);
 
-       nbytes = req->wb_bytes;
+       nbytes = count;
        do {
                size_t len = min(nbytes,rsize);
 
-               data = nfs_readdata_alloc(len);
+               data = nfs_readdata_alloc(1);
                if (!data)
                        goto out_bad;
                INIT_LIST_HEAD(&data->pages);
@@ -258,23 +261,19 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
 
        ClearPageError(page);
        offset = 0;
-       nbytes = req->wb_bytes;
+       nbytes = count;
        do {
                data = list_entry(list.next, struct nfs_read_data, pages);
                list_del_init(&data->pages);
 
                data->pagevec[0] = page;
 
-               if (nbytes > rsize) {
-                       nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
-                                       rsize, offset);
-                       offset += rsize;
-                       nbytes -= rsize;
-               } else {
-                       nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
-                                       nbytes, offset);
-                       nbytes = 0;
-               }
+               if (nbytes < rsize)
+                       rsize = nbytes;
+               nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
+                                 rsize, offset);
+               offset += rsize;
+               nbytes -= rsize;
                nfs_execute_read(data);
        } while (nbytes != 0);
 
@@ -291,30 +290,24 @@ out_bad:
        return -ENOMEM;
 }
 
-static int nfs_pagein_one(struct list_head *head, struct inode *inode)
+static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
 {
        struct nfs_page         *req;
        struct page             **pages;
        struct nfs_read_data    *data;
-       unsigned int            count;
 
-       if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
-               return nfs_pagein_multi(head, inode);
-
-       data = nfs_readdata_alloc(NFS_SERVER(inode)->rsize);
+       data = nfs_readdata_alloc(npages);
        if (!data)
                goto out_bad;
 
        INIT_LIST_HEAD(&data->pages);
        pages = data->pagevec;
-       count = 0;
        while (!list_empty(head)) {
                req = nfs_list_entry(head->next);
                nfs_list_remove_request(req);
                nfs_list_add_request(req, &data->pages);
                ClearPageError(req->wb_page);
                *pages++ = req->wb_page;
-               count += req->wb_bytes;
        }
        req = nfs_list_entry(data->pages.next);
 
@@ -327,28 +320,6 @@ out_bad:
        return -ENOMEM;
 }
 
-static int
-nfs_pagein_list(struct list_head *head, int rpages)
-{
-       LIST_HEAD(one_request);
-       struct nfs_page         *req;
-       int                     error = 0;
-       unsigned int            pages = 0;
-
-       while (!list_empty(head)) {
-               pages += nfs_coalesce_requests(head, &one_request, rpages);
-               req = nfs_list_entry(one_request.next);
-               error = nfs_pagein_one(&one_request, req->wb_context->dentry->d_inode);
-               if (error < 0)
-                       break;
-       }
-       if (error >= 0)
-               return pages;
-
-       nfs_async_read_error(head);
-       return error;
-}
-
 /*
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
@@ -538,7 +509,7 @@ out_error:
 }
 
 struct nfs_readdesc {
-       struct list_head *head;
+       struct nfs_pageio_descriptor *pgio;
        struct nfs_open_context *ctx;
 };
 
@@ -562,19 +533,21 @@ readpage_async_filler(void *data, struct page *page)
        }
        if (len < PAGE_CACHE_SIZE)
                memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
-       nfs_list_add_request(new, desc->head);
+       nfs_pageio_add_request(desc->pgio, new);
        return 0;
 }
 
 int nfs_readpages(struct file *filp, struct address_space *mapping,
                struct list_head *pages, unsigned nr_pages)
 {
-       LIST_HEAD(head);
+       struct nfs_pageio_descriptor pgio;
        struct nfs_readdesc desc = {
-               .head           = &head,
+               .pgio = &pgio,
        };
        struct inode *inode = mapping->host;
        struct nfs_server *server = NFS_SERVER(inode);
+       size_t rsize = server->rsize;
+       unsigned long npages;
        int ret = -ESTALE;
 
        dprintk("NFS: nfs_readpages (%s/%Ld %d)\n",
@@ -593,13 +566,16 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
        } else
                desc.ctx = get_nfs_open_context((struct nfs_open_context *)
                                filp->private_data);
+       if (rsize < PAGE_CACHE_SIZE)
+               nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
+       else
+               nfs_pageio_init(&pgio, inode, nfs_pagein_one, rsize, 0);
+
        ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
-       if (!list_empty(&head)) {
-               int err = nfs_pagein_list(&head, server->rpages);
-               if (!ret)
-                       nfs_add_stats(inode, NFSIOS_READPAGES, err);
-                       ret = err;
-       }
+
+       nfs_pageio_complete(&pgio);
+       npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       nfs_add_stats(inode, NFSIOS_READPAGES, npages);
        put_nfs_open_context(desc.ctx);
 out:
        return ret;
index f1eae44b9a1aec5167dfefb934437ccaedba2576..ca20d3cc260908b485f7d3bf4279ad3d718d97c4 100644 (file)
@@ -204,9 +204,9 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        lock_kernel();
 
        error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
-       buf->f_type = NFS_SUPER_MAGIC;
        if (error < 0)
                goto out_err;
+       buf->f_type = NFS_SUPER_MAGIC;
 
        /*
         * Current versions of glibc do not correctly handle the
@@ -233,15 +233,14 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_ffree = res.afiles;
 
        buf->f_namelen = server->namelen;
- out:
+
        unlock_kernel();
        return 0;
 
  out_err:
        dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
-       buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
-       goto out;
-
+       unlock_kernel();
+       return error;
 }
 
 /*
@@ -291,6 +290,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                { NFS_MOUNT_NOAC, ",noac", "" },
                { NFS_MOUNT_NONLM, ",nolock", "" },
                { NFS_MOUNT_NOACL, ",noacl", "" },
+               { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
                { 0, NULL, NULL }
        };
        const struct proc_nfs_info *nfs_infop;
index 797558941745a7b7a27fe0a931086680dc03eb42..5d44b8bd107093c72ac5d0aa50f23a20025ec609 100644 (file)
@@ -38,7 +38,8 @@
 static struct nfs_page * nfs_update_request(struct nfs_open_context*,
                                            struct page *,
                                            unsigned int, unsigned int);
-static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how);
+static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc,
+                                 struct inode *inode, int ioflags);
 static const struct rpc_call_ops nfs_write_partial_ops;
 static const struct rpc_call_ops nfs_write_full_ops;
 static const struct rpc_call_ops nfs_commit_ops;
@@ -71,9 +72,8 @@ void nfs_commit_free(struct nfs_write_data *wdata)
        call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free);
 }
 
-struct nfs_write_data *nfs_writedata_alloc(size_t len)
+struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
 {
-       unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);
 
        if (p) {
@@ -139,7 +139,7 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c
 {
        struct inode *inode = page->mapping->host;
        loff_t end, i_size = i_size_read(inode);
-       unsigned long end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
+       pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
 
        if (i_size > 0 && page->index < end_index)
                return;
@@ -201,7 +201,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
 static int wb_priority(struct writeback_control *wbc)
 {
        if (wbc->for_reclaim)
-               return FLUSH_HIGHPRI;
+               return FLUSH_HIGHPRI | FLUSH_STABLE;
        if (wbc->for_kupdate)
                return FLUSH_LOWPRI;
        return 0;
@@ -251,7 +251,8 @@ static void nfs_end_page_writeback(struct page *page)
  * was not tagged.
  * May also return an error if the user signalled nfs_wait_on_request().
  */
-static int nfs_page_mark_flush(struct page *page)
+static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
+                               struct page *page)
 {
        struct nfs_page *req;
        struct nfs_inode *nfsi = NFS_I(page->mapping->host);
@@ -273,6 +274,8 @@ static int nfs_page_mark_flush(struct page *page)
                 *       request as dirty (in which case we don't care).
                 */
                spin_unlock(req_lock);
+               /* Prevent deadlock! */
+               nfs_pageio_complete(pgio);
                ret = nfs_wait_on_request(req);
                nfs_release_request(req);
                if (ret != 0)
@@ -283,21 +286,18 @@ static int nfs_page_mark_flush(struct page *page)
                /* This request is marked for commit */
                spin_unlock(req_lock);
                nfs_unlock_request(req);
+               nfs_pageio_complete(pgio);
                return 1;
        }
-       if (nfs_set_page_writeback(page) == 0) {
-               nfs_list_remove_request(req);
-               /* add the request to the inode's dirty list. */
-               radix_tree_tag_set(&nfsi->nfs_page_tree,
-                               req->wb_index, NFS_PAGE_TAG_DIRTY);
-               nfs_list_add_request(req, &nfsi->dirty);
-               nfsi->ndirty++;
-               spin_unlock(req_lock);
-               __mark_inode_dirty(page->mapping->host, I_DIRTY_PAGES);
-       } else
+       if (nfs_set_page_writeback(page) != 0) {
                spin_unlock(req_lock);
+               BUG();
+       }
+       radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
+                       NFS_PAGE_TAG_WRITEBACK);
        ret = test_bit(PG_NEED_FLUSH, &req->wb_flags);
-       nfs_unlock_request(req);
+       spin_unlock(req_lock);
+       nfs_pageio_add_request(pgio, req);
        return ret;
 }
 
@@ -306,6 +306,7 @@ static int nfs_page_mark_flush(struct page *page)
  */
 static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
 {
+       struct nfs_pageio_descriptor mypgio, *pgio;
        struct nfs_open_context *ctx;
        struct inode *inode = page->mapping->host;
        unsigned offset;
@@ -314,7 +315,14 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
        nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
 
-       err = nfs_page_mark_flush(page);
+       if (wbc->for_writepages)
+               pgio = wbc->fs_private;
+       else {
+               nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc));
+               pgio = &mypgio;
+       }
+
+       err = nfs_page_async_flush(pgio, page);
        if (err <= 0)
                goto out;
        err = 0;
@@ -331,12 +339,12 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
        put_nfs_open_context(ctx);
        if (err != 0)
                goto out;
-       err = nfs_page_mark_flush(page);
+       err = nfs_page_async_flush(pgio, page);
        if (err > 0)
                err = 0;
 out:
        if (!wbc->for_writepages)
-               nfs_flush_mapping(page->mapping, wbc, FLUSH_STABLE|wb_priority(wbc));
+               nfs_pageio_complete(pgio);
        return err;
 }
 
@@ -352,20 +360,20 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
 int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
        struct inode *inode = mapping->host;
+       struct nfs_pageio_descriptor pgio;
        int err;
 
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
 
+       nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
+       wbc->fs_private = &pgio;
        err = generic_writepages(mapping, wbc);
+       nfs_pageio_complete(&pgio);
        if (err)
                return err;
-       err = nfs_flush_mapping(mapping, wbc, wb_priority(wbc));
-       if (err < 0)
-               goto out;
-       nfs_add_stats(inode, NFSIOS_WRITEPAGES, err);
-       err = 0;
-out:
-       return err;
+       if (pgio.pg_error)
+               return pgio.pg_error;
+       return 0;
 }
 
 /*
@@ -503,11 +511,11 @@ int nfs_reschedule_unstable_write(struct nfs_page *req)
  *
  * Interruptible by signals only if mounted with intr flag.
  */
-static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_start, unsigned int npages)
+static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_page *req;
-       unsigned long           idx_end, next;
+       pgoff_t idx_end, next;
        unsigned int            res = 0;
        int                     error;
 
@@ -536,18 +544,6 @@ static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_st
        return res;
 }
 
-static void nfs_cancel_dirty_list(struct list_head *head)
-{
-       struct nfs_page *req;
-       while(!list_empty(head)) {
-               req = nfs_list_entry(head->next);
-               nfs_list_remove_request(req);
-               nfs_end_page_writeback(req->wb_page);
-               nfs_inode_remove_request(req);
-               nfs_clear_page_writeback(req);
-       }
-}
-
 static void nfs_cancel_commit_list(struct list_head *head)
 {
        struct nfs_page *req;
@@ -574,7 +570,7 @@ static void nfs_cancel_commit_list(struct list_head *head)
  * The requests are *not* checked to ensure that they form a contiguous set.
  */
 static int
-nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
+nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        int res = 0;
@@ -588,40 +584,12 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_st
        return res;
 }
 #else
-static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
+static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 {
        return 0;
 }
 #endif
 
-static int nfs_wait_on_write_congestion(struct address_space *mapping)
-{
-       struct inode *inode = mapping->host;
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
-       int ret = 0;
-
-       might_sleep();
-
-       if (!bdi_write_congested(bdi))
-               return 0;
-
-       nfs_inc_stats(inode, NFSIOS_CONGESTIONWAIT);
-
-       do {
-               struct rpc_clnt *clnt = NFS_CLIENT(inode);
-               sigset_t oldset;
-
-               rpc_clnt_sigmask(clnt, &oldset);
-               ret = congestion_wait_interruptible(WRITE, HZ/10);
-               rpc_clnt_sigunmask(clnt, &oldset);
-               if (ret == -ERESTARTSYS)
-                       break;
-               ret = 0;
-       } while (bdi_write_congested(bdi));
-
-       return ret;
-}
-
 /*
  * Try to update any existing write request, or create one if there is none.
  * In order to match, the request's credentials must match those of
@@ -636,12 +604,10 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
        struct inode *inode = mapping->host;
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_page         *req, *new = NULL;
-       unsigned long           rqend, end;
+       pgoff_t         rqend, end;
 
        end = offset + bytes;
 
-       if (nfs_wait_on_write_congestion(mapping))
-               return ERR_PTR(-ERESTARTSYS);
        for (;;) {
                /* Loop over all inode entries and see if we find
                 * A request for the page we wish to update
@@ -865,7 +831,7 @@ static void nfs_execute_write(struct nfs_write_data *data)
  * Generate multiple small requests to write out a single
  * contiguous dirty area on one page.
  */
-static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how)
+static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
 {
        struct nfs_page *req = nfs_list_entry(head->next);
        struct page *page = req->wb_page;
@@ -877,11 +843,11 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how)
 
        nfs_list_remove_request(req);
 
-       nbytes = req->wb_bytes;
+       nbytes = count;
        do {
                size_t len = min(nbytes, wsize);
 
-               data = nfs_writedata_alloc(len);
+               data = nfs_writedata_alloc(1);
                if (!data)
                        goto out_bad;
                list_add(&data->pages, &list);
@@ -892,23 +858,19 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how)
 
        ClearPageError(page);
        offset = 0;
-       nbytes = req->wb_bytes;
+       nbytes = count;
        do {
                data = list_entry(list.next, struct nfs_write_data, pages);
                list_del_init(&data->pages);
 
                data->pagevec[0] = page;
 
-               if (nbytes > wsize) {
-                       nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
-                                       wsize, offset, how);
-                       offset += wsize;
-                       nbytes -= wsize;
-               } else {
-                       nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
-                                       nbytes, offset, how);
-                       nbytes = 0;
-               }
+               if (nbytes < wsize)
+                       wsize = nbytes;
+               nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
+                                  wsize, offset, how);
+               offset += wsize;
+               nbytes -= wsize;
                nfs_execute_write(data);
        } while (nbytes != 0);
 
@@ -934,26 +896,23 @@ out_bad:
  * This is the case if nfs_updatepage detects a conflicting request
  * that has been written but not committed.
  */
-static int nfs_flush_one(struct inode *inode, struct list_head *head, int how)
+static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
 {
        struct nfs_page         *req;
        struct page             **pages;
        struct nfs_write_data   *data;
-       unsigned int            count;
 
-       data = nfs_writedata_alloc(NFS_SERVER(inode)->wsize);
+       data = nfs_writedata_alloc(npages);
        if (!data)
                goto out_bad;
 
        pages = data->pagevec;
-       count = 0;
        while (!list_empty(head)) {
                req = nfs_list_entry(head->next);
                nfs_list_remove_request(req);
                nfs_list_add_request(req, &data->pages);
                ClearPageError(req->wb_page);
                *pages++ = req->wb_page;
-               count += req->wb_bytes;
        }
        req = nfs_list_entry(data->pages.next);
 
@@ -973,40 +932,15 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how)
        return -ENOMEM;
 }
 
-static int nfs_flush_list(struct inode *inode, struct list_head *head, int npages, int how)
+static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
+                                 struct inode *inode, int ioflags)
 {
-       LIST_HEAD(one_request);
-       int (*flush_one)(struct inode *, struct list_head *, int);
-       struct nfs_page *req;
-       int wpages = NFS_SERVER(inode)->wpages;
        int wsize = NFS_SERVER(inode)->wsize;
-       int error;
 
-       flush_one = nfs_flush_one;
        if (wsize < PAGE_CACHE_SIZE)
-               flush_one = nfs_flush_multi;
-       /* For single writes, FLUSH_STABLE is more efficient */
-       if (npages <= wpages && npages == NFS_I(inode)->npages
-                       && nfs_list_entry(head->next)->wb_bytes <= wsize)
-               how |= FLUSH_STABLE;
-
-       do {
-               nfs_coalesce_requests(head, &one_request, wpages);
-               req = nfs_list_entry(one_request.next);
-               error = flush_one(inode, &one_request, how);
-               if (error < 0)
-                       goto out_err;
-       } while (!list_empty(head));
-       return 0;
-out_err:
-       while (!list_empty(head)) {
-               req = nfs_list_entry(head->next);
-               nfs_list_remove_request(req);
-               nfs_redirty_request(req);
-               nfs_end_page_writeback(req->wb_page);
-               nfs_clear_page_writeback(req);
-       }
-       return error;
+               nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags);
+       else
+               nfs_pageio_init(pgio, inode, nfs_flush_one, wsize, ioflags);
 }
 
 /*
@@ -1330,31 +1264,7 @@ static const struct rpc_call_ops nfs_commit_ops = {
        .rpc_call_done = nfs_commit_done,
        .rpc_release = nfs_commit_release,
 };
-#else
-static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how)
-{
-       return 0;
-}
-#endif
-
-static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how)
-{
-       struct nfs_inode *nfsi = NFS_I(mapping->host);
-       LIST_HEAD(head);
-       long res;
-
-       spin_lock(&nfsi->req_lock);
-       res = nfs_scan_dirty(mapping, wbc, &head);
-       spin_unlock(&nfsi->req_lock);
-       if (res) {
-               int error = nfs_flush_list(mapping->host, &head, res, how);
-               if (error < 0)
-                       return error;
-       }
-       return res;
-}
 
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 int nfs_commit_inode(struct inode *inode, int how)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -1371,13 +1281,18 @@ int nfs_commit_inode(struct inode *inode, int how)
        }
        return res;
 }
+#else
+static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how)
+{
+       return 0;
+}
 #endif
 
 long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how)
 {
        struct inode *inode = mapping->host;
        struct nfs_inode *nfsi = NFS_I(inode);
-       unsigned long idx_start, idx_end;
+       pgoff_t idx_start, idx_end;
        unsigned int npages = 0;
        LIST_HEAD(head);
        int nocommit = how & FLUSH_NOCOMMIT;
@@ -1390,41 +1305,24 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr
                idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
                idx_end = wbc->range_end >> PAGE_CACHE_SHIFT;
                if (idx_end > idx_start) {
-                       unsigned long l_npages = 1 + idx_end - idx_start;
+                       pgoff_t l_npages = 1 + idx_end - idx_start;
                        npages = l_npages;
                        if (sizeof(npages) != sizeof(l_npages) &&
-                                       (unsigned long)npages != l_npages)
+                                       (pgoff_t)npages != l_npages)
                                npages = 0;
                }
        }
        how &= ~FLUSH_NOCOMMIT;
        spin_lock(&nfsi->req_lock);
        do {
-               wbc->pages_skipped = 0;
                ret = nfs_wait_on_requests_locked(inode, idx_start, npages);
                if (ret != 0)
                        continue;
-               pages = nfs_scan_dirty(mapping, wbc, &head);
-               if (pages != 0) {
-                       spin_unlock(&nfsi->req_lock);
-                       if (how & FLUSH_INVALIDATE) {
-                               nfs_cancel_dirty_list(&head);
-                               ret = pages;
-                       } else
-                               ret = nfs_flush_list(inode, &head, pages, how);
-                       spin_lock(&nfsi->req_lock);
-                       continue;
-               }
-               if (wbc->pages_skipped != 0)
-                       continue;
                if (nocommit)
                        break;
                pages = nfs_scan_commit(inode, &head, idx_start, npages);
-               if (pages == 0) {
-                       if (wbc->pages_skipped != 0)
-                               continue;
+               if (pages == 0)
                        break;
-               }
                if (how & FLUSH_INVALIDATE) {
                        spin_unlock(&nfsi->req_lock);
                        nfs_cancel_commit_list(&head);
@@ -1456,7 +1354,7 @@ int nfs_wb_all(struct inode *inode)
        };
        int ret;
 
-       ret = generic_writepages(mapping, &wbc);
+       ret = nfs_writepages(mapping, &wbc);
        if (ret < 0)
                goto out;
        ret = nfs_sync_mapping_wait(mapping, &wbc, 0);
@@ -1479,11 +1377,9 @@ int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, lo
        };
        int ret;
 
-       if (!(how & FLUSH_NOWRITEPAGE)) {
-               ret = generic_writepages(mapping, &wbc);
-               if (ret < 0)
-                       goto out;
-       }
+       ret = nfs_writepages(mapping, &wbc);
+       if (ret < 0)
+               goto out;
        ret = nfs_sync_mapping_wait(mapping, &wbc, how);
        if (ret >= 0)
                return 0;
@@ -1506,7 +1402,7 @@ int nfs_wb_page_priority(struct inode *inode, struct page *page, int how)
        int ret;
 
        BUG_ON(!PageLocked(page));
-       if (!(how & FLUSH_NOWRITEPAGE) && clear_page_dirty_for_io(page)) {
+       if (clear_page_dirty_for_io(page)) {
                ret = nfs_writepage_locked(page, &wbc);
                if (ret < 0)
                        goto out;
@@ -1531,10 +1427,18 @@ int nfs_wb_page(struct inode *inode, struct page* page)
 
 int nfs_set_page_dirty(struct page *page)
 {
-       spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock;
+       struct address_space *mapping = page->mapping;
+       struct inode *inode;
+       spinlock_t *req_lock;
        struct nfs_page *req;
        int ret;
 
+       if (!mapping)
+               goto out_raced;
+       inode = mapping->host;
+       if (!inode)
+               goto out_raced;
+       req_lock = &NFS_I(inode)->req_lock;
        spin_lock(req_lock);
        req = nfs_page_find_request_locked(page);
        if (req != NULL) {
@@ -1547,6 +1451,8 @@ int nfs_set_page_dirty(struct page *page)
        ret = __set_page_dirty_nobuffers(page);
        spin_unlock(req_lock);
        return ret;
+out_raced:
+       return !TestSetPageDirty(page);
 }
 
 
index fb14d68eacab846db08f92bbcdca7a1aff56e43c..32ffea033c7a9ca628cb5553daa740d73bb6994d 100644 (file)
@@ -315,16 +315,13 @@ out:
 /*
  * RPC procedure tables
  */
-#ifndef MAX
-# define MAX(a, b)      (((a) > (b))? (a) : (b))
-#endif
-
 #define PROC(proc, call, argtype, restype)                              \
 [NFSPROC4_CLNT_##proc] = {                                             \
         .p_proc   = NFSPROC4_CB_##call,                                        \
         .p_encode = (kxdrproc_t) nfs4_xdr_##argtype,                    \
         .p_decode = (kxdrproc_t) nfs4_xdr_##restype,                    \
-        .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2,  \
+        .p_arglen = NFS4_##argtype##_sz,                                \
+        .p_replen = NFS4_##restype##_sz,                                \
         .p_statidx = NFSPROC4_CB_##call,                               \
        .p_name   = #proc,                                              \
 }
index ac25b5649c594a65589ec25f8079a9642333e447..f6a81e0b1b9325c196cdd10c26b4826eff6f251c 100644 (file)
@@ -88,7 +88,7 @@ struct nlm_wait;
 /*
  * Memory chunk for NLM client RPC request.
  */
-#define NLMCLNT_OHSIZE         (sizeof(utsname()->nodename)+10)
+#define NLMCLNT_OHSIZE         ((__NEW_UTS_LEN) + 10u)
 struct nlm_rqst {
        unsigned int            a_flags;        /* initial RPC task flags */
        struct nlm_host *       a_host;         /* host handle */
index e9ae0c6e2c62048a9410df000cac3b8350e70c69..0543439a97aff58b508ce54af24111b1145a7eee 100644 (file)
@@ -455,7 +455,7 @@ nfs_have_writebacks(struct inode *inode)
 /*
  * Allocate nfs_write_data structures
  */
-extern struct nfs_write_data *nfs_writedata_alloc(size_t len);
+extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages);
 
 /*
  * linux/fs/nfs/read.c
@@ -469,7 +469,7 @@ extern void nfs_readdata_release(void *data);
 /*
  * Allocate nfs_read_data structures
  */
-extern struct nfs_read_data *nfs_readdata_alloc(size_t len);
+extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages);
 
 /*
  * linux/fs/nfs3proc.c
index 659c7543845482f236b63386b1212caeff147870..cc8b9c59acb8607005e7a891efbb74b29ac6a994 100644 (file)
@@ -61,6 +61,7 @@ struct nfs_mount_data {
 #define NFS_MOUNT_NOACL                0x0800  /* 4 */
 #define NFS_MOUNT_STRICTLOCK   0x1000  /* reserved for NFSv4 */
 #define NFS_MOUNT_SECFLAVOUR   0x2000  /* 5 */
+#define NFS_MOUNT_NORDIRPLUS   0x4000  /* 5 */
 #define NFS_MOUNT_FLAGMASK     0xFFFF
 
 #endif
index 16b0266b14fd9b8845cf7f45efe509772b883e98..41afab6b5f09c2cf3dbcde8bab5ee4eb896eaf44 100644 (file)
@@ -21,8 +21,7 @@
 /*
  * Valid flags for the radix tree
  */
-#define NFS_PAGE_TAG_DIRTY     0
-#define NFS_PAGE_TAG_WRITEBACK 1
+#define NFS_PAGE_TAG_WRITEBACK 0
 
 /*
  * Valid flags for a dirty buffer
@@ -39,7 +38,7 @@ struct nfs_page {
        struct page             *wb_page;       /* page to read in/write out */
        struct nfs_open_context *wb_context;    /* File state context info */
        atomic_t                wb_complete;    /* i/os we're waiting for */
-       unsigned long           wb_index;       /* Offset >> PAGE_CACHE_SHIFT */
+       pgoff_t                 wb_index;       /* Offset >> PAGE_CACHE_SHIFT */
        unsigned int            wb_offset,      /* Offset & ~PAGE_CACHE_MASK */
                                wb_pgbase,      /* Start of page data */
                                wb_bytes;       /* Length of request */
@@ -48,6 +47,19 @@ struct nfs_page {
        struct nfs_writeverf    wb_verf;        /* Commit cookie */
 };
 
+struct nfs_pageio_descriptor {
+       struct list_head        pg_list;
+       unsigned long           pg_bytes_written;
+       size_t                  pg_count;
+       size_t                  pg_bsize;
+       unsigned int            pg_base;
+
+       struct inode            *pg_inode;
+       int                     (*pg_doio)(struct inode *, struct list_head *, unsigned int, size_t, int);
+       int                     pg_ioflags;
+       int                     pg_error;
+};
+
 #define NFS_WBACK_BUSY(req)    (test_bit(PG_BUSY,&(req)->wb_flags))
 
 extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
@@ -59,13 +71,16 @@ extern      void nfs_clear_request(struct nfs_page *req);
 extern void nfs_release_request(struct nfs_page *req);
 
 
-extern long nfs_scan_dirty(struct address_space *mapping,
-                               struct writeback_control *wbc,
-                               struct list_head *dst);
 extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst,
-                         unsigned long idx_start, unsigned int npages);
-extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
-                                 unsigned int);
+                         pgoff_t idx_start, unsigned int npages);
+extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
+                            struct inode *inode,
+                            int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+                            size_t bsize,
+                            int how);
+extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
+                                  struct nfs_page *);
+extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc);
 extern  int nfs_wait_on_request(struct nfs_page *);
 extern void nfs_unlock_request(struct nfs_page *req);
 extern  int nfs_set_page_writeback_locked(struct nfs_page *req);
index c7a78eef2b4faf21171c175607a249d4b5c983bf..66611423c8ee3763a9bcc8390d9ffab9f85cd0a7 100644 (file)
@@ -84,7 +84,8 @@ struct rpc_procinfo {
        u32                     p_proc;         /* RPC procedure number */
        kxdrproc_t              p_encode;       /* XDR encode function */
        kxdrproc_t              p_decode;       /* XDR decode function */
-       unsigned int            p_bufsiz;       /* req. buffer size */
+       unsigned int            p_arglen;       /* argument hdr length (u32) */
+       unsigned int            p_replen;       /* reply hdr length (u32) */
        unsigned int            p_count;        /* call count */
        unsigned int            p_timer;        /* Which RTT timer to use */
        u32                     p_statidx;      /* Which procedure to account */
@@ -121,8 +122,8 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
 int            rpc_shutdown_client(struct rpc_clnt *);
 int            rpc_destroy_client(struct rpc_clnt *);
 void           rpc_release_client(struct rpc_clnt *);
-void           rpc_getport(struct rpc_task *);
-int            rpc_register(u32, u32, int, unsigned short, int *);
+int            rpcb_register(u32, u32, int, unsigned short, int *);
+void           rpcb_getport(struct rpc_task *);
 
 void           rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
 
@@ -144,7 +145,7 @@ char *              rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
 /*
  * Helper function for NFSroot support
  */
-int            rpc_getport_external(struct sockaddr_in *, __u32, __u32, int);
+int            rpcb_getport_external(struct sockaddr_in *, __u32, __u32, int);
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_CLNT_H */
index b7c7307ceec6bc8865104713559d800d6e1967c8..3912cf16361ee98aa9334399fe6d8289e3270364 100644 (file)
@@ -17,7 +17,7 @@
 #define RPCDBG_DEBUG           0x0004
 #define RPCDBG_NFS             0x0008
 #define RPCDBG_AUTH            0x0010
-#define RPCDBG_PMAP            0x0020
+#define RPCDBG_BIND            0x0020
 #define RPCDBG_SCHED           0x0040
 #define RPCDBG_TRANS           0x0080
 #define RPCDBG_SVCSOCK         0x0100
index 606cb21652322d33ed1d389e44b6c304d4fb6b8f..784d4c3ef651126829b76083e898590d2e00314c 100644 (file)
@@ -78,10 +78,6 @@ enum rpc_auth_stat {
        RPCSEC_GSS_CTXPROBLEM = 14
 };
 
-#define RPC_PMAP_PROGRAM       100000
-#define RPC_PMAP_VERSION       2
-#define RPC_PMAP_PORT          111
-
 #define RPC_MAXNETNAMELEN      256
 
 /*
index 3069ecca0129e9c46bf69223870c0788183ea3b3..2047fb202a137c048264b77036b3072849d21f3c 100644 (file)
@@ -264,7 +264,7 @@ struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
 void           rpc_wake_up_status(struct rpc_wait_queue *, int);
 void           rpc_delay(struct rpc_task *, unsigned long);
 void *         rpc_malloc(struct rpc_task *, size_t);
-void           rpc_free(struct rpc_task *);
+void           rpc_free(void *);
 int            rpciod_up(void);
 void           rpciod_down(void);
 int            __rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *));
index f780e72fc417e44b1701edd63d9af1ef271f703e..fa89ce6ce076cb61ac98ebb80d85af3e33f524be 100644 (file)
@@ -84,7 +84,9 @@ struct rpc_rqst {
        struct list_head        rq_list;
 
        __u32 *                 rq_buffer;      /* XDR encode buffer */
-       size_t                  rq_bufsize;
+       size_t                  rq_bufsize,
+                               rq_callsize,
+                               rq_rcvsize;
 
        struct xdr_buf          rq_private_buf;         /* The receive buffer
                                                         * used in the softirq.
@@ -112,7 +114,7 @@ struct rpc_xprt_ops {
        void            (*set_port)(struct rpc_xprt *xprt, unsigned short port);
        void            (*connect)(struct rpc_task *task);
        void *          (*buf_alloc)(struct rpc_task *task, size_t size);
-       void            (*buf_free)(struct rpc_task *task);
+       void            (*buf_free)(void *buffer);
        int             (*send_request)(struct rpc_task *task);
        void            (*set_retrans_timeout)(struct rpc_task *task);
        void            (*timer)(struct rpc_task *task);
@@ -150,6 +152,7 @@ struct rpc_xprt {
        unsigned long           state;          /* transport state */
        unsigned char           shutdown   : 1, /* being shut down */
                                resvport   : 1; /* use a reserved port */
+       unsigned int            bind_index;     /* bind function index */
 
        /*
         * Connection of transports
index 0c78f7f4a976489064d2508d6e56ae610bf84311..daa6c125f66e937e26884aeaeabab2b4525f72c0 100644 (file)
@@ -59,6 +59,8 @@ struct writeback_control {
        unsigned for_reclaim:1;         /* Invoked from the page allocator */
        unsigned for_writepages:1;      /* This is a writepages() call */
        unsigned range_cyclic:1;        /* range_start is cyclic */
+
+       void *fs_private;               /* For use by ->writepages() */
 };
 
 /*
index cdcab9ca4c60fed14b460da6a4c93794b18bf938..8ebfc4db7f5199274cd0cea30a4c5fa6ec066d47 100644 (file)
@@ -9,7 +9,7 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
 sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
            auth.o auth_null.o auth_unix.o \
            svc.o svcsock.o svcauth.o svcauth_unix.o \
-           pmap_clnt.o timer.o xdr.o \
+           rpcb_clnt.o timer.o xdr.o \
            sunrpc_syms.o cache.o rpc_pipe.o
 sunrpc-$(CONFIG_PROC_FS) += stats.o
 sunrpc-$(CONFIG_SYSCTL) += sysctl.o
index 104cbf4f769fa21d5b6029f57dd741995006f9c0..d158635de6c08dc8a66a0b2f89fd79bed0f12d78 100644 (file)
@@ -123,9 +123,6 @@ spkm3_make_token(struct spkm3_ctx *ctx,
 
        return  GSS_S_COMPLETE;
 out_err:
-       if (md5cksum.data)
-               kfree(md5cksum.data);
-
        token->data = NULL;
        token->len = 0;
        return GSS_S_FAILURE;
@@ -152,7 +149,7 @@ make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
 
        switch (cksumtype) {
                case CKSUMTYPE_HMAC_MD5:
-                       cksumname = "md5";
+                       cksumname = "hmac(md5)";
                        break;
                default:
                        dprintk("RPC:       spkm3_make_checksum:"
@@ -172,8 +169,12 @@ make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
        if (err)
                goto out;
 
+       err = crypto_hash_init(&desc);
+       if (err)
+               goto out;
+
        sg_set_buf(sg, header, hdrlen);
-       crypto_hash_update(&desc, sg, 1);
+       crypto_hash_update(&desc, sg, sg->length);
 
        xdr_process_buf(body, body_offset, body->len - body_offset,
                        spkm3_checksummer, &desc);
@@ -184,5 +185,3 @@ out:
 
        return err ? GSS_S_FAILURE : 0;
 }
-
-EXPORT_SYMBOL(make_spkm3_checksum);
index 396cdbe249d10a6a255a3431d58cc3c266cff6a9..d8fbee40a19cecf2a46200783a65c817e1c97504 100644 (file)
@@ -36,8 +36,6 @@
 #include <linux/sunrpc/metrics.h>
 
 
-#define RPC_SLACK_SPACE                (1024)  /* total overkill */
-
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_CALL
 #endif
@@ -747,21 +745,38 @@ call_reserveresult(struct rpc_task *task)
 static void
 call_allocate(struct rpc_task *task)
 {
+       unsigned int slack = task->tk_auth->au_cslack;
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = task->tk_xprt;
-       unsigned int    bufsiz;
+       struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
 
        dprint_status(task);
 
+       task->tk_status = 0;
        task->tk_action = call_bind;
+
        if (req->rq_buffer)
                return;
 
-       /* FIXME: compute buffer requirements more exactly using
-        * auth->au_wslack */
-       bufsiz = task->tk_msg.rpc_proc->p_bufsiz + RPC_SLACK_SPACE;
+       if (proc->p_proc != 0) {
+               BUG_ON(proc->p_arglen == 0);
+               if (proc->p_decode != NULL)
+                       BUG_ON(proc->p_replen == 0);
+       }
 
-       if (xprt->ops->buf_alloc(task, bufsiz << 1) != NULL)
+       /*
+        * Calculate the size (in quads) of the RPC call
+        * and reply headers, and convert both values
+        * to byte sizes.
+        */
+       req->rq_callsize = RPC_CALLHDRSIZE + (slack << 1) + proc->p_arglen;
+       req->rq_callsize <<= 2;
+       req->rq_rcvsize = RPC_REPHDRSIZE + slack + proc->p_replen;
+       req->rq_rcvsize <<= 2;
+
+       req->rq_buffer = xprt->ops->buf_alloc(task,
+                                       req->rq_callsize + req->rq_rcvsize);
+       if (req->rq_buffer != NULL)
                return;
 
        dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid);
@@ -788,6 +803,17 @@ rpc_task_force_reencode(struct rpc_task *task)
        task->tk_rqstp->rq_snd_buf.len = 0;
 }
 
+static inline void
+rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
+{
+       buf->head[0].iov_base = start;
+       buf->head[0].iov_len = len;
+       buf->tail[0].iov_len = 0;
+       buf->page_len = 0;
+       buf->len = 0;
+       buf->buflen = len;
+}
+
 /*
  * 3.  Encode arguments of an RPC call
  */
@@ -795,28 +821,17 @@ static void
 call_encode(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
-       struct xdr_buf *sndbuf = &req->rq_snd_buf;
-       struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
-       unsigned int    bufsiz;
        kxdrproc_t      encode;
        __be32          *p;
 
        dprint_status(task);
 
-       /* Default buffer setup */
-       bufsiz = req->rq_bufsize >> 1;
-       sndbuf->head[0].iov_base = (void *)req->rq_buffer;
-       sndbuf->head[0].iov_len  = bufsiz;
-       sndbuf->tail[0].iov_len  = 0;
-       sndbuf->page_len         = 0;
-       sndbuf->len              = 0;
-       sndbuf->buflen           = bufsiz;
-       rcvbuf->head[0].iov_base = (void *)((char *)req->rq_buffer + bufsiz);
-       rcvbuf->head[0].iov_len  = bufsiz;
-       rcvbuf->tail[0].iov_len  = 0;
-       rcvbuf->page_len         = 0;
-       rcvbuf->len              = 0;
-       rcvbuf->buflen           = bufsiz;
+       rpc_xdr_buf_init(&req->rq_snd_buf,
+                        req->rq_buffer,
+                        req->rq_callsize);
+       rpc_xdr_buf_init(&req->rq_rcv_buf,
+                        (char *)req->rq_buffer + req->rq_callsize,
+                        req->rq_rcvsize);
 
        /* Encode header and provided arguments */
        encode = task->tk_msg.rpc_proc->p_encode;
@@ -887,9 +902,11 @@ call_bind_status(struct rpc_task *task)
                                task->tk_pid);
                break;
        case -EPROTONOSUPPORT:
-               dprintk("RPC: %5u remote rpcbind version 2 unavailable\n",
+               dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n",
                                task->tk_pid);
-               break;
+               task->tk_status = 0;
+               task->tk_action = call_bind;
+               return;
        default:
                dprintk("RPC: %5u unrecognized rpcbind error (%d)\n",
                                task->tk_pid, -task->tk_status);
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
deleted file mode 100644 (file)
index d9f7653..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * linux/net/sunrpc/pmap_clnt.c
- *
- * In-kernel RPC portmapper client.
- *
- * Portmapper supports version 2 of the rpcbind protocol (RFC 1833).
- *
- * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/uio.h>
-#include <linux/in.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/sched.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY       RPCDBG_PMAP
-#endif
-
-#define PMAP_SET               1
-#define PMAP_UNSET             2
-#define PMAP_GETPORT           3
-
-struct portmap_args {
-       u32                     pm_prog;
-       u32                     pm_vers;
-       u32                     pm_prot;
-       unsigned short          pm_port;
-       struct rpc_xprt *       pm_xprt;
-};
-
-static struct rpc_procinfo     pmap_procedures[];
-static struct rpc_clnt *       pmap_create(char *, struct sockaddr_in *, int, int);
-static void                    pmap_getport_done(struct rpc_task *, void *);
-static struct rpc_program      pmap_program;
-
-static void pmap_getport_prepare(struct rpc_task *task, void *calldata)
-{
-       struct portmap_args *map = calldata;
-       struct rpc_message msg = {
-               .rpc_proc       = &pmap_procedures[PMAP_GETPORT],
-               .rpc_argp       = map,
-               .rpc_resp       = &map->pm_port,
-       };
-
-       rpc_call_setup(task, &msg, 0);
-}
-
-static inline struct portmap_args *pmap_map_alloc(void)
-{
-       return kmalloc(sizeof(struct portmap_args), GFP_NOFS);
-}
-
-static inline void pmap_map_free(struct portmap_args *map)
-{
-       kfree(map);
-}
-
-static void pmap_map_release(void *data)
-{
-       struct portmap_args *map = data;
-
-       xprt_put(map->pm_xprt);
-       pmap_map_free(map);
-}
-
-static const struct rpc_call_ops pmap_getport_ops = {
-       .rpc_call_prepare       = pmap_getport_prepare,
-       .rpc_call_done          = pmap_getport_done,
-       .rpc_release            = pmap_map_release,
-};
-
-static inline void pmap_wake_portmap_waiters(struct rpc_xprt *xprt, int status)
-{
-       xprt_clear_binding(xprt);
-       rpc_wake_up_status(&xprt->binding, status);
-}
-
-/**
- * rpc_getport - obtain the port for a given RPC service on a given host
- * @task: task that is waiting for portmapper request
- *
- * This one can be called for an ongoing RPC request, and can be used in
- * an async (rpciod) context.
- */
-void rpc_getport(struct rpc_task *task)
-{
-       struct rpc_clnt *clnt = task->tk_client;
-       struct rpc_xprt *xprt = task->tk_xprt;
-       struct sockaddr_in addr;
-       struct portmap_args *map;
-       struct rpc_clnt *pmap_clnt;
-       struct rpc_task *child;
-       int status;
-
-       dprintk("RPC: %5u rpc_getport(%s, %u, %u, %d)\n",
-                       task->tk_pid, clnt->cl_server,
-                       clnt->cl_prog, clnt->cl_vers, xprt->prot);
-
-       /* Autobind on cloned rpc clients is discouraged */
-       BUG_ON(clnt->cl_parent != clnt);
-
-       status = -EACCES;               /* tell caller to check again */
-       if (xprt_test_and_set_binding(xprt))
-               goto bailout_nowake;
-
-       /* Put self on queue before sending rpcbind request, in case
-        * pmap_getport_done completes before we return from rpc_run_task */
-       rpc_sleep_on(&xprt->binding, task, NULL, NULL);
-
-       /* Someone else may have bound if we slept */
-       status = 0;
-       if (xprt_bound(xprt))
-               goto bailout_nofree;
-
-       status = -ENOMEM;
-       map = pmap_map_alloc();
-       if (!map)
-               goto bailout_nofree;
-       map->pm_prog = clnt->cl_prog;
-       map->pm_vers = clnt->cl_vers;
-       map->pm_prot = xprt->prot;
-       map->pm_port = 0;
-       map->pm_xprt = xprt_get(xprt);
-
-       rpc_peeraddr(clnt, (struct sockaddr *) &addr, sizeof(addr));
-       pmap_clnt = pmap_create(clnt->cl_server, &addr, map->pm_prot, 0);
-       status = PTR_ERR(pmap_clnt);
-       if (IS_ERR(pmap_clnt))
-               goto bailout;
-
-       status = -EIO;
-       child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
-       if (IS_ERR(child))
-               goto bailout_nofree;
-       rpc_put_task(child);
-
-       task->tk_xprt->stat.bind_count++;
-       return;
-
-bailout:
-       pmap_map_free(map);
-       xprt_put(xprt);
-bailout_nofree:
-       pmap_wake_portmap_waiters(xprt, status);
-bailout_nowake:
-       task->tk_status = status;
-}
-
-#ifdef CONFIG_ROOT_NFS
-/**
- * rpc_getport_external - obtain the port for a given RPC service on a given host
- * @sin: address of remote peer
- * @prog: RPC program number to bind
- * @vers: RPC version number to bind
- * @prot: transport protocol to use to make this request
- *
- * This one is called from outside the RPC client in a synchronous task context.
- */
-int rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
-{
-       struct portmap_args map = {
-               .pm_prog        = prog,
-               .pm_vers        = vers,
-               .pm_prot        = prot,
-               .pm_port        = 0
-       };
-       struct rpc_message msg = {
-               .rpc_proc       = &pmap_procedures[PMAP_GETPORT],
-               .rpc_argp       = &map,
-               .rpc_resp       = &map.pm_port,
-       };
-       struct rpc_clnt *pmap_clnt;
-       char            hostname[32];
-       int             status;
-
-       dprintk("RPC:       rpc_getport_external(%u.%u.%u.%u, %u, %u, %d)\n",
-                       NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
-
-       sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
-       pmap_clnt = pmap_create(hostname, sin, prot, 0);
-       if (IS_ERR(pmap_clnt))
-               return PTR_ERR(pmap_clnt);
-
-       /* Setup the call info struct */
-       status = rpc_call_sync(pmap_clnt, &msg, 0);
-
-       if (status >= 0) {
-               if (map.pm_port != 0)
-                       return map.pm_port;
-               status = -EACCES;
-       }
-       return status;
-}
-#endif
-
-/*
- * Portmapper child task invokes this callback via tk_exit.
- */
-static void pmap_getport_done(struct rpc_task *child, void *data)
-{
-       struct portmap_args *map = data;
-       struct rpc_xprt *xprt = map->pm_xprt;
-       int status = child->tk_status;
-
-       if (status < 0) {
-               /* Portmapper not available */
-               xprt->ops->set_port(xprt, 0);
-       } else if (map->pm_port == 0) {
-               /* Requested RPC service wasn't registered */
-               xprt->ops->set_port(xprt, 0);
-               status = -EACCES;
-       } else {
-               /* Succeeded */
-               xprt->ops->set_port(xprt, map->pm_port);
-               xprt_set_bound(xprt);
-               status = 0;
-       }
-
-       dprintk("RPC: %5u pmap_getport_done(status %d, port %u)\n",
-                       child->tk_pid, status, map->pm_port);
-
-       pmap_wake_portmap_waiters(xprt, status);
-}
-
-/**
- * rpc_register - set or unset a port registration with the local portmapper
- * @prog: RPC program number to bind
- * @vers: RPC version number to bind
- * @prot: transport protocol to use to make this request
- * @port: port value to register
- * @okay: result code
- *
- * port == 0 means unregister, port != 0 means register.
- */
-int rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
-{
-       struct sockaddr_in      sin = {
-               .sin_family     = AF_INET,
-               .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
-       };
-       struct portmap_args     map = {
-               .pm_prog        = prog,
-               .pm_vers        = vers,
-               .pm_prot        = prot,
-               .pm_port        = port,
-       };
-       struct rpc_message msg = {
-               .rpc_proc       = &pmap_procedures[port ? PMAP_SET : PMAP_UNSET],
-               .rpc_argp       = &map,
-               .rpc_resp       = okay,
-       };
-       struct rpc_clnt         *pmap_clnt;
-       int error = 0;
-
-       dprintk("RPC:       registering (%u, %u, %d, %u) with portmapper.\n",
-                       prog, vers, prot, port);
-
-       pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1);
-       if (IS_ERR(pmap_clnt)) {
-               error = PTR_ERR(pmap_clnt);
-               dprintk("RPC:       couldn't create pmap client. Error = %d\n",
-                               error);
-               return error;
-       }
-
-       error = rpc_call_sync(pmap_clnt, &msg, 0);
-
-       if (error < 0) {
-               printk(KERN_WARNING
-                       "RPC: failed to contact portmap (errno %d).\n",
-                       error);
-       }
-       dprintk("RPC:       registration status %d/%d\n", error, *okay);
-
-       /* Client deleted automatically because cl_oneshot == 1 */
-       return error;
-}
-
-static struct rpc_clnt *pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged)
-{
-       struct rpc_create_args args = {
-               .protocol       = proto,
-               .address        = (struct sockaddr *)srvaddr,
-               .addrsize       = sizeof(*srvaddr),
-               .servername     = hostname,
-               .program        = &pmap_program,
-               .version        = RPC_PMAP_VERSION,
-               .authflavor     = RPC_AUTH_UNIX,
-               .flags          = (RPC_CLNT_CREATE_ONESHOT |
-                                  RPC_CLNT_CREATE_NOPING),
-       };
-
-       srvaddr->sin_port = htons(RPC_PMAP_PORT);
-       if (!privileged)
-               args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
-       return rpc_create(&args);
-}
-
-/*
- * XDR encode/decode functions for PMAP
- */
-static int xdr_encode_mapping(struct rpc_rqst *req, __be32 *p, struct portmap_args *map)
-{
-       dprintk("RPC:       xdr_encode_mapping(%u, %u, %u, %u)\n",
-                       map->pm_prog, map->pm_vers,
-                       map->pm_prot, map->pm_port);
-       *p++ = htonl(map->pm_prog);
-       *p++ = htonl(map->pm_vers);
-       *p++ = htonl(map->pm_prot);
-       *p++ = htonl(map->pm_port);
-
-       req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-       return 0;
-}
-
-static int xdr_decode_port(struct rpc_rqst *req, __be32 *p, unsigned short *portp)
-{
-       *portp = (unsigned short) ntohl(*p++);
-       return 0;
-}
-
-static int xdr_decode_bool(struct rpc_rqst *req, __be32 *p, unsigned int *boolp)
-{
-       *boolp = (unsigned int) ntohl(*p++);
-       return 0;
-}
-
-static struct rpc_procinfo     pmap_procedures[] = {
-[PMAP_SET] = {
-         .p_proc               = PMAP_SET,
-         .p_encode             = (kxdrproc_t) xdr_encode_mapping,
-         .p_decode             = (kxdrproc_t) xdr_decode_bool,
-         .p_bufsiz             = 4,
-         .p_count              = 1,
-         .p_statidx            = PMAP_SET,
-         .p_name               = "SET",
-       },
-[PMAP_UNSET] = {
-         .p_proc               = PMAP_UNSET,
-         .p_encode             = (kxdrproc_t) xdr_encode_mapping,
-         .p_decode             = (kxdrproc_t) xdr_decode_bool,
-         .p_bufsiz             = 4,
-         .p_count              = 1,
-         .p_statidx            = PMAP_UNSET,
-         .p_name               = "UNSET",
-       },
-[PMAP_GETPORT] = {
-         .p_proc               = PMAP_GETPORT,
-         .p_encode             = (kxdrproc_t) xdr_encode_mapping,
-         .p_decode             = (kxdrproc_t) xdr_decode_port,
-         .p_bufsiz             = 4,
-         .p_count              = 1,
-         .p_statidx            = PMAP_GETPORT,
-         .p_name               = "GETPORT",
-       },
-};
-
-static struct rpc_version      pmap_version2 = {
-       .number         = 2,
-       .nrprocs        = 4,
-       .procs          = pmap_procedures
-};
-
-static struct rpc_version *    pmap_version[] = {
-       NULL,
-       NULL,
-       &pmap_version2
-};
-
-static struct rpc_stat         pmap_stats;
-
-static struct rpc_program      pmap_program = {
-       .name           = "portmap",
-       .number         = RPC_PMAP_PROGRAM,
-       .nrvers         = ARRAY_SIZE(pmap_version),
-       .version        = pmap_version,
-       .stats          = &pmap_stats,
-};
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
new file mode 100644 (file)
index 0000000..6c7aa8a
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ * In-kernel rpcbind client supporting versions 2, 3, and 4 of the rpcbind
+ * protocol
+ *
+ * Based on RFC 1833: "Binding Protocols for ONC RPC Version 2" and
+ * RFC 3530: "Network File System (NFS) version 4 Protocol"
+ *
+ * Original: Gilles Quillard, Bull Open Source, 2005 <gilles.quillard@bull.net>
+ * Updated: Chuck Lever, Oracle Corporation, 2007 <chuck.lever@oracle.com>
+ *
+ * Descended from net/sunrpc/pmap_clnt.c,
+ *  Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/sched.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY       RPCDBG_BIND
+#endif
+
+#define RPCBIND_PROGRAM                (100000u)
+#define RPCBIND_PORT           (111u)
+
+enum {
+       RPCBPROC_NULL,
+       RPCBPROC_SET,
+       RPCBPROC_UNSET,
+       RPCBPROC_GETPORT,
+       RPCBPROC_GETADDR = 3,           /* alias for GETPORT */
+       RPCBPROC_DUMP,
+       RPCBPROC_CALLIT,
+       RPCBPROC_BCAST = 5,             /* alias for CALLIT */
+       RPCBPROC_GETTIME,
+       RPCBPROC_UADDR2TADDR,
+       RPCBPROC_TADDR2UADDR,
+       RPCBPROC_GETVERSADDR,
+       RPCBPROC_INDIRECT,
+       RPCBPROC_GETADDRLIST,
+       RPCBPROC_GETSTAT,
+};
+
+#define RPCB_HIGHPROC_2                RPCBPROC_CALLIT
+#define RPCB_HIGHPROC_3                RPCBPROC_TADDR2UADDR
+#define RPCB_HIGHPROC_4                RPCBPROC_GETSTAT
+
+/*
+ * r_addr
+ *
+ * Quoting RFC 3530, section 2.2:
+ *
+ * For TCP over IPv4 and for UDP over IPv4, the format of r_addr is the
+ * US-ASCII string:
+ *
+ *     h1.h2.h3.h4.p1.p2
+ *
+ * The prefix, "h1.h2.h3.h4", is the standard textual form for
+ * representing an IPv4 address, which is always four octets long.
+ * Assuming big-endian ordering, h1, h2, h3, and h4, are respectively,
+ * the first through fourth octets each converted to ASCII-decimal.
+ * Assuming big-endian ordering, p1 and p2 are, respectively, the first
+ * and second octets each converted to ASCII-decimal.  For example, if a
+ * host, in big-endian order, has an address of 0x0A010307 and there is
+ * a service listening on, in big endian order, port 0x020F (decimal
+ * 527), then the complete universal address is "10.1.3.7.2.15".
+ *
+ * ...
+ *
+ * For TCP over IPv6 and for UDP over IPv6, the format of r_addr is the
+ * US-ASCII string:
+ *
+ *     x1:x2:x3:x4:x5:x6:x7:x8.p1.p2
+ *
+ * The suffix "p1.p2" is the service port, and is computed the same way
+ * as with universal addresses for TCP and UDP over IPv4.  The prefix,
+ * "x1:x2:x3:x4:x5:x6:x7:x8", is the standard textual form for
+ * representing an IPv6 address as defined in Section 2.2 of [RFC2373].
+ * Additionally, the two alternative forms specified in Section 2.2 of
+ * [RFC2373] are also acceptable.
+ *
+ * XXX: Currently this implementation does not explicitly convert the
+ *      stored address to US-ASCII on non-ASCII systems.
+ */
+#define RPCB_MAXADDRLEN                (128u)
+
+/*
+ * r_netid
+ *
+ * Quoting RFC 3530, section 2.2:
+ *
+ * For TCP over IPv4 the value of r_netid is the string "tcp".  For UDP
+ * over IPv4 the value of r_netid is the string "udp".
+ *
+ * ...
+ *
+ * For TCP over IPv6 the value of r_netid is the string "tcp6".  For UDP
+ * over IPv6 the value of r_netid is the string "udp6".
+ */
+#define RPCB_NETID_UDP "\165\144\160"          /* "udp" */
+#define RPCB_NETID_TCP "\164\143\160"          /* "tcp" */
+#define RPCB_NETID_UDP6        "\165\144\160\066"      /* "udp6" */
+#define RPCB_NETID_TCP6        "\164\143\160\066"      /* "tcp6" */
+
+#define RPCB_MAXNETIDLEN       (4u)
+
+/*
+ * r_owner
+ *
+ * The "owner" is allowed to unset a service in the rpcbind database.
+ * We always use the following (arbitrary) fixed string.
+ */
+#define RPCB_OWNER_STRING      "rpcb"
+#define RPCB_MAXOWNERLEN       sizeof(RPCB_OWNER_STRING)
+
+static void                    rpcb_getport_done(struct rpc_task *, void *);
+extern struct rpc_program      rpcb_program;
+
+struct rpcbind_args {
+       struct rpc_xprt *       r_xprt;
+
+       u32                     r_prog;
+       u32                     r_vers;
+       u32                     r_prot;
+       unsigned short          r_port;
+       char *                  r_netid;
+       char                    r_addr[RPCB_MAXADDRLEN];
+       char *                  r_owner;
+};
+
+static struct rpc_procinfo rpcb_procedures2[];
+static struct rpc_procinfo rpcb_procedures3[];
+
+static struct rpcb_info {
+       int                     rpc_vers;
+       struct rpc_procinfo *   rpc_proc;
+} rpcb_next_version[];
+
+static void rpcb_getport_prepare(struct rpc_task *task, void *calldata)
+{
+       struct rpcbind_args *map = calldata;
+       struct rpc_xprt *xprt = map->r_xprt;
+       struct rpc_message msg = {
+               .rpc_proc       = rpcb_next_version[xprt->bind_index].rpc_proc,
+               .rpc_argp       = map,
+               .rpc_resp       = &map->r_port,
+       };
+
+       rpc_call_setup(task, &msg, 0);
+}
+
+static void rpcb_map_release(void *data)
+{
+       struct rpcbind_args *map = data;
+
+       xprt_put(map->r_xprt);
+       kfree(map);
+}
+
+static const struct rpc_call_ops rpcb_getport_ops = {
+       .rpc_call_prepare       = rpcb_getport_prepare,
+       .rpc_call_done          = rpcb_getport_done,
+       .rpc_release            = rpcb_map_release,
+};
+
+static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
+{
+       xprt_clear_binding(xprt);
+       rpc_wake_up_status(&xprt->binding, status);
+}
+
+static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
+                                       int proto, int version, int privileged)
+{
+       struct rpc_create_args args = {
+               .protocol       = proto,
+               .address        = srvaddr,
+               .addrsize       = sizeof(struct sockaddr_in),
+               .servername     = hostname,
+               .program        = &rpcb_program,
+               .version        = version,
+               .authflavor     = RPC_AUTH_UNIX,
+               .flags          = (RPC_CLNT_CREATE_ONESHOT |
+                                  RPC_CLNT_CREATE_NOPING),
+       };
+
+       ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
+       if (!privileged)
+               args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
+       return rpc_create(&args);
+}
+
+/**
+ * rpcb_register - set or unset a port registration with the local rpcbind svc
+ * @prog: RPC program number to bind
+ * @vers: RPC version number to bind
+ * @prot: transport protocol to use to make this request
+ * @port: port value to register
+ * @okay: result code
+ *
+ * port == 0 means unregister, port != 0 means register.
+ *
+ * This routine supports only rpcbind version 2.
+ */
+int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
+{
+       struct sockaddr_in sin = {
+               .sin_family             = AF_INET,
+               .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
+       };
+       struct rpcbind_args map = {
+               .r_prog         = prog,
+               .r_vers         = vers,
+               .r_prot         = prot,
+               .r_port         = port,
+       };
+       struct rpc_message msg = {
+               .rpc_proc       = &rpcb_procedures2[port ?
+                                       RPCBPROC_SET : RPCBPROC_UNSET],
+               .rpc_argp       = &map,
+               .rpc_resp       = okay,
+       };
+       struct rpc_clnt *rpcb_clnt;
+       int error = 0;
+
+       dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
+                       "rpcbind\n", (port ? "" : "un"),
+                       prog, vers, prot, port);
+
+       rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
+                                       IPPROTO_UDP, 2, 1);
+       if (IS_ERR(rpcb_clnt))
+               return PTR_ERR(rpcb_clnt);
+
+       error = rpc_call_sync(rpcb_clnt, &msg, 0);
+
+       if (error < 0)
+               printk(KERN_WARNING "RPC: failed to contact local rpcbind "
+                               "server (errno %d).\n", -error);
+       dprintk("RPC:       registration status %d/%d\n", error, *okay);
+
+       return error;
+}
+
+#ifdef CONFIG_ROOT_NFS
+/**
+ * rpcb_getport_external - obtain the port for an RPC service on a given host
+ * @sin: address of remote peer
+ * @prog: RPC program number to bind
+ * @vers: RPC version number to bind
+ * @prot: transport protocol to use to make this request
+ *
+ * Called from outside the RPC client in a synchronous task context.
+ *
+ * For now, this supports only version 2 queries, but is used only by
+ * mount_clnt for NFS_ROOT.
+ */
+int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog,
+                               __u32 vers, int prot)
+{
+       struct rpcbind_args map = {
+               .r_prog         = prog,
+               .r_vers         = vers,
+               .r_prot         = prot,
+               .r_port         = 0,
+       };
+       struct rpc_message msg = {
+               .rpc_proc       = &rpcb_procedures2[RPCBPROC_GETPORT],
+               .rpc_argp       = &map,
+               .rpc_resp       = &map.r_port,
+       };
+       struct rpc_clnt *rpcb_clnt;
+       char hostname[40];
+       int status;
+
+       dprintk("RPC:       rpcb_getport_external(%u.%u.%u.%u, %u, %u, %d)\n",
+                       NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+
+       sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
+       rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0);
+       if (IS_ERR(rpcb_clnt))
+               return PTR_ERR(rpcb_clnt);
+
+       status = rpc_call_sync(rpcb_clnt, &msg, 0);
+
+       if (status >= 0) {
+               if (map.r_port != 0)
+                       return map.r_port;
+               status = -EACCES;
+       }
+       return status;
+}
+#endif
+
+/**
+ * rpcb_getport - obtain the port for a given RPC service on a given host
+ * @task: task that is waiting for portmapper request
+ *
+ * This one can be called for an ongoing RPC request, and can be used in
+ * an async (rpciod) context.
+ */
+void rpcb_getport(struct rpc_task *task)
+{
+       struct rpc_clnt *clnt = task->tk_client;
+       int bind_version;
+       struct rpc_xprt *xprt = task->tk_xprt;
+       struct rpc_clnt *rpcb_clnt;
+       static struct rpcbind_args *map;
+       struct rpc_task *child;
+       struct sockaddr addr;
+       int status;
+
+       dprintk("RPC: %5u rpcb_getport(%s, %u, %u, %d)\n",
+                       task->tk_pid, clnt->cl_server,
+                       clnt->cl_prog, clnt->cl_vers, xprt->prot);
+
+       /* Autobind on cloned rpc clients is discouraged */
+       BUG_ON(clnt->cl_parent != clnt);
+
+       if (xprt_test_and_set_binding(xprt)) {
+               status = -EACCES;               /* tell caller to check again */
+               dprintk("RPC: %5u rpcb_getport waiting for another binder\n",
+                               task->tk_pid);
+               goto bailout_nowake;
+       }
+
+       /* Put self on queue before sending rpcbind request, in case
+        * rpcb_getport_done completes before we return from rpc_run_task */
+       rpc_sleep_on(&xprt->binding, task, NULL, NULL);
+
+       /* Someone else may have bound if we slept */
+       if (xprt_bound(xprt)) {
+               status = 0;
+               dprintk("RPC: %5u rpcb_getport already bound\n", task->tk_pid);
+               goto bailout_nofree;
+       }
+
+       if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) {
+               xprt->bind_index = 0;
+               status = -EACCES;       /* tell caller to try again later */
+               dprintk("RPC: %5u rpcb_getport no more getport versions "
+                               "available\n", task->tk_pid);
+               goto bailout_nofree;
+       }
+       bind_version = rpcb_next_version[xprt->bind_index].rpc_vers;
+
+       dprintk("RPC: %5u rpcb_getport trying rpcbind version %u\n",
+                       task->tk_pid, bind_version);
+
+       map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
+       if (!map) {
+               status = -ENOMEM;
+               dprintk("RPC: %5u rpcb_getport no memory available\n",
+                               task->tk_pid);
+               goto bailout_nofree;
+       }
+       map->r_prog = clnt->cl_prog;
+       map->r_vers = clnt->cl_vers;
+       map->r_prot = xprt->prot;
+       map->r_port = 0;
+       map->r_xprt = xprt_get(xprt);
+       map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCB_NETID_TCP :
+                                                  RPCB_NETID_UDP;
+       memcpy(&map->r_addr, rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR),
+                       sizeof(map->r_addr));
+       map->r_owner = RPCB_OWNER_STRING;       /* ignored for GETADDR */
+
+       rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
+       rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
+       if (IS_ERR(rpcb_clnt)) {
+               status = PTR_ERR(rpcb_clnt);
+               dprintk("RPC: %5u rpcb_getport rpcb_create failed, error %ld\n",
+                               task->tk_pid, PTR_ERR(rpcb_clnt));
+               goto bailout;
+       }
+
+       child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
+       if (IS_ERR(child)) {
+               status = -EIO;
+               dprintk("RPC: %5u rpcb_getport rpc_run_task failed\n",
+                               task->tk_pid);
+               goto bailout_nofree;
+       }
+       rpc_put_task(child);
+
+       task->tk_xprt->stat.bind_count++;
+       return;
+
+bailout:
+       kfree(map);
+       xprt_put(xprt);
+bailout_nofree:
+       rpcb_wake_rpcbind_waiters(xprt, status);
+bailout_nowake:
+       task->tk_status = status;
+}
+
+/*
+ * Rpcbind child task calls this callback via tk_exit.
+ */
+static void rpcb_getport_done(struct rpc_task *child, void *data)
+{
+       struct rpcbind_args *map = data;
+       struct rpc_xprt *xprt = map->r_xprt;
+       int status = child->tk_status;
+
+       /* rpcbind server doesn't support this rpcbind protocol version */
+       if (status == -EPROTONOSUPPORT)
+               xprt->bind_index++;
+
+       if (status < 0) {
+               /* rpcbind server not available on remote host? */
+               xprt->ops->set_port(xprt, 0);
+       } else if (map->r_port == 0) {
+               /* Requested RPC service wasn't registered on remote host */
+               xprt->ops->set_port(xprt, 0);
+               status = -EACCES;
+       } else {
+               /* Succeeded */
+               xprt->ops->set_port(xprt, map->r_port);
+               xprt_set_bound(xprt);
+               status = 0;
+       }
+
+       dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n",
+                       child->tk_pid, status, map->r_port);
+
+       rpcb_wake_rpcbind_waiters(xprt, status);
+}
+
+static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
+                              struct rpcbind_args *rpcb)
+{
+       dprintk("RPC:       rpcb_encode_mapping(%u, %u, %d, %u)\n",
+                       rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
+       *p++ = htonl(rpcb->r_prog);
+       *p++ = htonl(rpcb->r_vers);
+       *p++ = htonl(rpcb->r_prot);
+       *p++ = htonl(rpcb->r_port);
+
+       req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+       return 0;
+}
+
+static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
+                              unsigned short *portp)
+{
+       *portp = (unsigned short) ntohl(*p++);
+       dprintk("RPC:      rpcb_decode_getport result %u\n",
+                       *portp);
+       return 0;
+}
+
+static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
+                          unsigned int *boolp)
+{
+       *boolp = (unsigned int) ntohl(*p++);
+       dprintk("RPC:      rpcb_decode_set result %u\n",
+                       *boolp);
+       return 0;
+}
+
+static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
+                              struct rpcbind_args *rpcb)
+{
+       dprintk("RPC:       rpcb_encode_getaddr(%u, %u, %s)\n",
+                       rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
+       *p++ = htonl(rpcb->r_prog);
+       *p++ = htonl(rpcb->r_vers);
+
+       p = xdr_encode_string(p, rpcb->r_netid);
+       p = xdr_encode_string(p, rpcb->r_addr);
+       p = xdr_encode_string(p, rpcb->r_owner);
+
+       req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+       return 0;
+}
+
+static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
+                              unsigned short *portp)
+{
+       char *addr;
+       int addr_len, c, i, f, first, val;
+
+       *portp = 0;
+       addr_len = (unsigned int) ntohl(*p++);
+       if (addr_len > RPCB_MAXADDRLEN)                 /* sanity */
+               return -EINVAL;
+
+       dprintk("RPC:       rpcb_decode_getaddr returned string: '%s'\n",
+                       (char *) p);
+
+       addr = (char *)p;
+       val = 0;
+       first = 1;
+       f = 1;
+       for (i = addr_len - 1; i > 0; i--) {
+               c = addr[i];
+               if (c >= '0' && c <= '9') {
+                       val += (c - '0') * f;
+                       f *= 10;
+               } else if (c == '.') {
+                       if (first) {
+                               *portp = val;
+                               val = first = 0;
+                               f = 1;
+                       } else {
+                               *portp |= (val << 8);
+                               break;
+                       }
+               }
+       }
+
+       dprintk("RPC:       rpcb_decode_getaddr port=%u\n", *portp);
+       return 0;
+}
+
+#define RPCB_program_sz                (1u)
+#define RPCB_version_sz                (1u)
+#define RPCB_protocol_sz       (1u)
+#define RPCB_port_sz           (1u)
+#define RPCB_boolean_sz                (1u)
+
+#define RPCB_netid_sz          (1+XDR_QUADLEN(RPCB_MAXNETIDLEN))
+#define RPCB_addr_sz           (1+XDR_QUADLEN(RPCB_MAXADDRLEN))
+#define RPCB_ownerstring_sz    (1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
+
+#define RPCB_mappingargs_sz    RPCB_program_sz+RPCB_version_sz+        \
+                               RPCB_protocol_sz+RPCB_port_sz
+#define RPCB_getaddrargs_sz    RPCB_program_sz+RPCB_version_sz+        \
+                               RPCB_netid_sz+RPCB_addr_sz+             \
+                               RPCB_ownerstring_sz
+
+#define RPCB_setres_sz         RPCB_boolean_sz
+#define RPCB_getportres_sz     RPCB_port_sz
+
+/*
+ * Note that RFC 1833 does not put any size restrictions on the
+ * address string returned by the remote rpcbind database.
+ */
+#define RPCB_getaddrres_sz     RPCB_addr_sz
+
+#define PROC(proc, argtype, restype)                                   \
+       [RPCBPROC_##proc] = {                                           \
+               .p_proc         = RPCBPROC_##proc,                      \
+               .p_encode       = (kxdrproc_t) rpcb_encode_##argtype,   \
+               .p_decode       = (kxdrproc_t) rpcb_decode_##restype,   \
+               .p_arglen       = RPCB_##argtype##args_sz,              \
+               .p_replen       = RPCB_##restype##res_sz,               \
+               .p_statidx      = RPCBPROC_##proc,                      \
+               .p_timer        = 0,                                    \
+               .p_name         = #proc,                                \
+       }
+
+/*
+ * Not all rpcbind procedures described in RFC 1833 are implemented
+ * since the Linux kernel RPC code requires only these.
+ */
+static struct rpc_procinfo rpcb_procedures2[] = {
+       PROC(SET,               mapping,        set),
+       PROC(UNSET,             mapping,        set),
+       PROC(GETADDR,           mapping,        getport),
+};
+
+static struct rpc_procinfo rpcb_procedures3[] = {
+       PROC(SET,               mapping,        set),
+       PROC(UNSET,             mapping,        set),
+       PROC(GETADDR,           getaddr,        getaddr),
+};
+
+static struct rpc_procinfo rpcb_procedures4[] = {
+       PROC(SET,               mapping,        set),
+       PROC(UNSET,             mapping,        set),
+       PROC(GETVERSADDR,       getaddr,        getaddr),
+};
+
+static struct rpcb_info rpcb_next_version[] = {
+#ifdef CONFIG_SUNRPC_BIND34
+       { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
+       { 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
+#endif
+       { 2, &rpcb_procedures2[RPCBPROC_GETPORT] },
+       { 0, NULL },
+};
+
+static struct rpc_version rpcb_version2 = {
+       .number         = 2,
+       .nrprocs        = RPCB_HIGHPROC_2,
+       .procs          = rpcb_procedures2
+};
+
+static struct rpc_version rpcb_version3 = {
+       .number         = 3,
+       .nrprocs        = RPCB_HIGHPROC_3,
+       .procs          = rpcb_procedures3
+};
+
+static struct rpc_version rpcb_version4 = {
+       .number         = 4,
+       .nrprocs        = RPCB_HIGHPROC_4,
+       .procs          = rpcb_procedures4
+};
+
+static struct rpc_version *rpcb_version[] = {
+       NULL,
+       NULL,
+       &rpcb_version2,
+       &rpcb_version3,
+       &rpcb_version4
+};
+
+static struct rpc_stat rpcb_stats;
+
+struct rpc_program rpcb_program = {
+       .name           = "rpcbind",
+       .number         = RPCBIND_PROGRAM,
+       .nrvers         = ARRAY_SIZE(rpcb_version),
+       .version        = rpcb_version,
+       .stats          = &rpcb_stats,
+};
index 6d87320074b1556f98280dde419157f6288a2cb7..4a53e94f813415ac757f5180bf0d20a3323ba2d2 100644 (file)
@@ -741,50 +741,53 @@ static void rpc_async_schedule(struct work_struct *work)
  * @task: RPC task that will use this buffer
  * @size: requested byte size
  *
- * We try to ensure that some NFS reads and writes can always proceed
- * by using a mempool when allocating 'small' buffers.
+ * To prevent rpciod from hanging, this allocator never sleeps,
+ * returning NULL if the request cannot be serviced immediately.
+ * The caller can arrange to sleep in a way that is safe for rpciod.
+ *
+ * Most requests are 'small' (under 2KiB) and can be serviced from a
+ * mempool, ensuring that NFS reads and writes can always proceed,
+ * and that there is good locality of reference for these buffers.
+ *
  * In order to avoid memory starvation triggering more writebacks of
- * NFS requests, we use GFP_NOFS rather than GFP_KERNEL.
+ * NFS requests, we avoid using GFP_KERNEL.
  */
-void * rpc_malloc(struct rpc_task *task, size_t size)
+void *rpc_malloc(struct rpc_task *task, size_t size)
 {
-       struct rpc_rqst *req = task->tk_rqstp;
-       gfp_t   gfp;
+       size_t *buf;
+       gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT;
 
-       if (task->tk_flags & RPC_TASK_SWAPPER)
-               gfp = GFP_ATOMIC;
+       size += sizeof(size_t);
+       if (size <= RPC_BUFFER_MAXSIZE)
+               buf = mempool_alloc(rpc_buffer_mempool, gfp);
        else
-               gfp = GFP_NOFS;
-
-       if (size > RPC_BUFFER_MAXSIZE) {
-               req->rq_buffer = kmalloc(size, gfp);
-               if (req->rq_buffer)
-                       req->rq_bufsize = size;
-       } else {
-               req->rq_buffer = mempool_alloc(rpc_buffer_mempool, gfp);
-               if (req->rq_buffer)
-                       req->rq_bufsize = RPC_BUFFER_MAXSIZE;
-       }
-       return req->rq_buffer;
+               buf = kmalloc(size, gfp);
+       *buf = size;
+       dprintk("RPC: %5u allocated buffer of size %u at %p\n",
+                       task->tk_pid, size, buf);
+       return (void *) ++buf;
 }
 
 /**
  * rpc_free - free buffer allocated via rpc_malloc
- * @task: RPC task with a buffer to be freed
+ * @buffer: buffer to free
  *
  */
-void rpc_free(struct rpc_task *task)
+void rpc_free(void *buffer)
 {
-       struct rpc_rqst *req = task->tk_rqstp;
+       size_t size, *buf = (size_t *) buffer;
 
-       if (req->rq_buffer) {
-               if (req->rq_bufsize == RPC_BUFFER_MAXSIZE)
-                       mempool_free(req->rq_buffer, rpc_buffer_mempool);
-               else
-                       kfree(req->rq_buffer);
-               req->rq_buffer = NULL;
-               req->rq_bufsize = 0;
-       }
+       if (!buffer)
+               return;
+       size = *buf;
+       buf--;
+
+       dprintk("RPC:       freeing buffer of size %u at %p\n",
+                       size, buf);
+       if (size <= RPC_BUFFER_MAXSIZE)
+               mempool_free(buf, rpc_buffer_mempool);
+       else
+               kfree(buf);
 }
 
 /*
index b4db53ff143577a06fd72d2ef83418b4de194e9d..b7503c103ae814f012041a6f8f02e073c1d1ab26 100644 (file)
@@ -757,7 +757,7 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
                        if (progp->pg_vers[i]->vs_hidden)
                                continue;
 
-                       error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
+                       error = rpcb_register(progp->pg_prog, i, proto, port, &dummy);
                        if (error < 0)
                                break;
                        if (port && !dummy) {
index 456a1451030806be9183bab642552ef1c7508c64..5b05b73e4c1d3f7a52c189e05b1ba55461c3270f 100644 (file)
@@ -823,7 +823,6 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
        req->rq_task    = task;
        req->rq_xprt    = xprt;
        req->rq_buffer  = NULL;
-       req->rq_bufsize = 0;
        req->rq_xid     = xprt_alloc_xid(xprt);
        req->rq_release_snd_buf = NULL;
        xprt_reset_majortimeo(req);
@@ -855,7 +854,7 @@ void xprt_release(struct rpc_task *task)
                mod_timer(&xprt->timer,
                                xprt->last_used + xprt->idle_timeout);
        spin_unlock_bh(&xprt->transport_lock);
-       xprt->ops->buf_free(task);
+       xprt->ops->buf_free(req->rq_buffer);
        task->tk_rqstp = NULL;
        if (req->rq_release_snd_buf)
                req->rq_release_snd_buf(req);
@@ -928,6 +927,7 @@ struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t si
        xprt->timer.data = (unsigned long) xprt;
        xprt->last_used = jiffies;
        xprt->cwnd = RPC_INITCWND;
+       xprt->bind_index = 0;
 
        rpc_init_wait_queue(&xprt->binding, "xprt_binding");
        rpc_init_wait_queue(&xprt->pending, "xprt_pending");
index a5a32029e7283e9ef2bf7b834fef64e202e3330d..cc33c5880abb477eb3cdb7d415e2f7df91f303b1 100644 (file)
@@ -1476,7 +1476,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
        .set_buffer_size        = xs_udp_set_buffer_size,
        .reserve_xprt           = xprt_reserve_xprt_cong,
        .release_xprt           = xprt_release_xprt_cong,
-       .rpcbind                = rpc_getport,
+       .rpcbind                = rpcb_getport,
        .set_port               = xs_set_port,
        .connect                = xs_connect,
        .buf_alloc              = rpc_malloc,
@@ -1493,7 +1493,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
 static struct rpc_xprt_ops xs_tcp_ops = {
        .reserve_xprt           = xprt_reserve_xprt,
        .release_xprt           = xs_tcp_release_xprt,
-       .rpcbind                = rpc_getport,
+       .rpcbind                = rpcb_getport,
        .set_port               = xs_set_port,
        .connect                = xs_connect,
        .buf_alloc              = rpc_malloc,