From 9f73fdbc1bdb9ff55f7851558ddd0891f2d294da Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 May 2002 06:03:42 -0700 Subject: [PATCH] Teach RPC client to send pages rather than iovecs. Stop rpciod from deadlocking against itself in map_new_virtual() on HIGHMEM systems. RPC client currently has to keep all pages that are scheduled for transmission kmap()ed into an iovec for the entire duration of the call. We only actually need to kmap() pages while making the (non-blocking) call to sock_sendmsg(). NOTE: When transmitting several pages in one RPC call, sock_sendmsg() requires us to kmap() *all* those pages at the same time. Opens for deadlocks between rpciod and some other process that also kmaps more than 1 page at a time. For the TCP case we can solve later by converting to TCP_CORK+sendpage(). include/linux/sunrpc/xdr.h Introduce 'struct xdr_buf' in order to allow RPC layer to handle pages directly. include/linux/sunrpc/xprt.h: Convert the RPC client send-buffer to the new format. net/sunrpc/clnt.c Initialize the new format RPC send-buffer. net/sunrpc/sunrpc_syms.c Export xdr_encode_pages() net/sunrpc/xdr.c xdr_kmap() kmap()+copy a struct xdr_buf into an iovec array. xdr_kunmap() clean up after xdr_kmap(). xdr_encode_pages() used to inline pages for transmission. net/sunrpc/xprt.c xprt_sendmsg() needs to kmap() the pages into an iovec for transmission. include/linux/nfs_xdr.h struct nfs_writeargs transmits full page information. Convert nfs_rpc_ops->write() to send pages. fs/nfs/write.c Adapt to new format nfs_writeargs / nfs_rpc_ops->write() fs/nfs/proc.c Convert nfs_proc_write(). fs/nfs/nfs2xdr.c Convert nfs_xdr_writeargs() fs/nfs/nfs3proc.c Convert nfs3_proc_write(). fs/nfs/nfs3xdr.c Convert nfs3_xdr_writeargs() Cheers, Trond --- include/linux/nfs_xdr.h | 8 ++++---- include/linux/sunrpc/xdr.h | 34 ++++++++++++++++++++++++++++++++++ include/linux/sunrpc/xprt.h | 8 ++++---- 3 files changed, 42 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 4c77c2081721..c61b4486ec12 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -87,8 +87,8 @@ struct nfs_writeargs { __u64 offset; __u32 count; enum nfs3_stable_how stable; - unsigned int nriov; - struct iovec iov[NFS_WRITE_MAXIOV]; + unsigned int pgbase; + struct page ** pages; }; struct nfs_writeverf { @@ -329,8 +329,8 @@ struct nfs_rpc_ops { void *buffer, int *eofp); int (*write) (struct inode *, struct rpc_cred *, struct nfs_fattr *, - int, loff_t, unsigned int, - void *buffer, struct nfs_writeverf *verfp); + int, unsigned int, unsigned int, + struct page *, struct nfs_writeverf *verfp); int (*commit) (struct inode *, struct nfs_fattr *, unsigned long, unsigned int); int (*create) (struct inode *, struct qstr *, struct iattr *, diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 69827d88dcae..880dba6e66ad 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -34,6 +34,31 @@ struct xdr_netobj { */ typedef int (*kxdrproc_t)(void *rqstp, u32 *data, void *obj); +/* + * Basic structure for transmission/reception of a client XDR message. + * Features a header (for a linear buffer containing RPC headers + * and the data payload for short messages), and then an array of + * pages. + * The tail iovec allows you to append data after the page array. Its + * main interest is for appending padding to the pages in order to + * satisfy the int_32-alignment requirements in RFC1832. + * + * For the future, we might want to string several of these together + * in a list if anybody wants to make use of NFSv4 COMPOUND + * operations and/or has a need for scatter/gather involving pages. + */ +struct xdr_buf { + struct iovec head[1], /* RPC header + non-page data */ + tail[1]; /* Appended after page data */ + + struct page ** pages; /* Array of contiguous pages */ + unsigned int page_base, /* Start of page data */ + page_len; /* Length of page data */ + + unsigned int len; /* Total length of data */ + +}; + /* * pre-xdr'ed macros. */ @@ -68,6 +93,9 @@ u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *); u32 * xdr_decode_netobj(u32 *p, struct xdr_netobj *); u32 * xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len); +void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int, + unsigned int); + /* * Decode 64bit quantities (NFSv3 support) */ @@ -99,6 +127,12 @@ xdr_adjust_iovec(struct iovec *iov, u32 *p) void xdr_shift_iovec(struct iovec *, int, size_t); void xdr_zero_iovec(struct iovec *, int, size_t); +/* + * XDR buffer helper functions + */ +extern int xdr_kmap(struct iovec *, struct xdr_buf *, unsigned int); +extern void xdr_kunmap(struct xdr_buf *, unsigned int); + #endif /* __KERNEL__ */ #endif /* _SUNRPC_XDR_H_ */ diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index f1a329b62b43..4e7496764b9f 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -13,6 +13,7 @@ #include #include #include +#include /* * Maximum number of iov's we use. @@ -87,7 +88,7 @@ struct rpc_rqst { */ struct rpc_xprt * rq_xprt; /* RPC client */ struct rpc_timeout rq_timeout; /* timeout parms */ - struct rpc_iov rq_snd_buf; /* send buffer */ + struct xdr_buf rq_snd_buf; /* send buffer */ struct rpc_iov rq_rcv_buf; /* recv buffer */ /* @@ -113,9 +114,8 @@ struct rpc_rqst { unsigned long rq_xtime; /* when transmitted */ #endif }; -#define rq_svec rq_snd_buf.io_vec -#define rq_snr rq_snd_buf.io_nr -#define rq_slen rq_snd_buf.io_len +#define rq_svec rq_snd_buf.head +#define rq_slen rq_snd_buf.len #define rq_rvec rq_rcv_buf.io_vec #define rq_rnr rq_rcv_buf.io_nr #define rq_rlen rq_rcv_buf.io_len -- cgit v1.2.3