From a9e61e25f9d2e7e43bf17625f5cb56c9e0a89b17 Mon Sep 17 00:00:00 2001 From: Felix Blyakher Date: Tue, 31 Mar 2009 15:12:56 -0500 Subject: lockd: call locks_release_private to cleanup per-filesystem state For every lock request lockd creates a new file_lock object in nlmsvc_setgrantargs() by copying the passed in file_lock with locks_copy_lock(). A filesystem can attach it's own lock_operations vector to the file_lock. It has to be cleaned up at the end of the file_lock's life. However, lockd doesn't do it today, yet it asserts in nlmclnt_release_lockargs() that the per-filesystem state is clean. This patch fixes it by exporting locks_release_private() and adding it to nlmsvc_freegrantargs(), to be symmetrical to creating a file_lock in nlmsvc_setgrantargs(). Signed-off-by: Felix Blyakher Signed-off-by: J. Bruce Fields --- include/linux/fs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/fs.h b/include/linux/fs.h index 5bed436f435..5ba615e8f53 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1108,6 +1108,7 @@ extern void locks_copy_lock(struct file_lock *, struct file_lock *); extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); extern void locks_remove_posix(struct file *, fl_owner_t); extern void locks_remove_flock(struct file *); +extern void locks_release_private(struct file_lock *); extern void posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); extern int posix_lock_file_wait(struct file *, struct file_lock *); -- cgit v1.2.3 From abc5c44d6284fab8fb21bcfc52c0f16f980637df Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 23 Apr 2009 19:31:25 -0400 Subject: SUNRPC: Fix error return value of svc_addr_len() The svc_addr_len() helper function returns -EAFNOSUPPORT if it doesn't recognize the address family of the passed-in socket address. However, the return type of this function is size_t, which means -EAFNOSUPPORT is turned into a very large positive value in this case. The check in svc_udp_recvfrom() to see if the return value is less than zero therefore won't work at all. Additionally, handle_connect_req() passes this value directly to memset(). This could cause memset() to clobber a large chunk of memory if svc_addr_len() has returned an error. Currently the address family of these addresses, however, is known to be supported long before handle_connect_req() is called, so this isn't a real risk. Change the error return value of svc_addr_len() to zero, which fits in the range of size_t, and is safer to pass to memset() directly. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svc_xprt.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 0d9cb6ef28b..d790c52525c 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -118,7 +118,7 @@ static inline unsigned short svc_addr_port(const struct sockaddr *sa) return 0; } -static inline size_t svc_addr_len(struct sockaddr *sa) +static inline size_t svc_addr_len(const struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: @@ -126,7 +126,8 @@ static inline size_t svc_addr_len(struct sockaddr *sa) case AF_INET6: return sizeof(struct sockaddr_in6); } - return -EAFNOSUPPORT; + + return 0; } static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt) -- cgit v1.2.3 From 335c54bdc4d3bacdbd619ec95cd0b352435bd37f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 23 Apr 2009 19:32:25 -0400 Subject: NFSD: Prevent a buffer overflow in svc_xprt_names() The svc_xprt_names() function can overflow its buffer if it's so near the end of the passed in buffer that the "name too long" string still doesn't fit. Of course, it could never tell if it was near the end of the passed in buffer, since its only caller passes in zero as the buffer length. Let's make this API a little safer. Change svc_xprt_names() so it *always* checks for a buffer overflow, and change its only caller to pass in the correct buffer length. If svc_xprt_names() does overflow its buffer, it now fails with an ENAMETOOLONG errno, instead of trying to write a message at the end of the buffer. I don't like this much, but I can't figure out a clean way that's always safe to return some of the names, *and* an indication that the buffer was not long enough. The displayed error when doing a 'cat /proc/fs/nfsd/portlist' is "File name too long". Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svc_xprt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index d790c52525c..2223ae0b5ed 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -83,7 +83,7 @@ int svc_port_is_privileged(struct sockaddr *sin); int svc_print_xprts(char *buf, int maxlen); struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, const sa_family_t af, const unsigned short port); -int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen); +int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); static inline void svc_xprt_get(struct svc_xprt *xprt) { -- cgit v1.2.3 From bfba9ab4c64f0e5c33930711e6c073c285e01fcf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 23 Apr 2009 19:32:33 -0400 Subject: SUNRPC: pass buffer size to svc_addsock() Adjust the synopsis of svc_addsock() to pass in the size of the output buffer. Add a documenting comment. This is a cosmetic change for now. A subsequent patch will make sure the buffer length is passed to one_sock_name(), where the length will actually be useful. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svcsock.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 483e10380aa..e23241c53f4 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -39,7 +39,8 @@ int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); void svc_sock_update_bufs(struct svc_serv *serv); int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose); -int svc_addsock(struct svc_serv *serv, int fd, char *name_return); +int svc_addsock(struct svc_serv *serv, const int fd, + char *name_return, const size_t len); void svc_init_xprt_sock(void); void svc_cleanup_xprt_sock(void); -- cgit v1.2.3 From 8435d34dbbe75678c3cdad3d53b1e7996a79b3bf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 23 Apr 2009 19:32:40 -0400 Subject: SUNRPC: pass buffer size to svc_sock_names() Adjust the synopsis of svc_sock_names() to pass in the size of the output buffer. Add a documenting comment. This is a cosmetic change for now. A subsequent patch will make sure the buffer length is passed to one_sock_name(), where the length will actually be useful. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svcsock.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index e23241c53f4..82716313894 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -38,7 +38,9 @@ int svc_recv(struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); void svc_sock_update_bufs(struct svc_serv *serv); -int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose); +int svc_sock_names(struct svc_serv *serv, char *buf, + const size_t buflen, + const char *toclose); int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, const size_t len); void svc_init_xprt_sock(void); -- cgit v1.2.3 From c654b8a9cba6002aad1c01919e4928a79a4a6dcf Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 16 Apr 2009 17:33:25 -0400 Subject: nfsd: support ext4 i_version ext4 supports a real NFSv4 change attribute, which is bumped whenever the ctime would be updated, including times when two updates arrive within a jiffy of each other. (Note that although ext4 has space for nanosecond-precision ctime, the real resolution is lower: it actually uses jiffies as the time-source.) This ensures clients will invalidate their caches when they need to. There is some fear that keeping the i_version up-to-date could have performance drawbacks, so for now it's turned on only by a mount option. We hope to do something better eventually. Signed-off-by: J. Bruce Fields Cc: Theodore Tso --- include/linux/nfsd/nfsfh.h | 7 +++++++ include/linux/nfsd/xdr4.h | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index afa19016c4a..8f641c90845 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -151,9 +151,15 @@ typedef struct svc_fh { __u64 fh_pre_size; /* size before operation */ struct timespec fh_pre_mtime; /* mtime before oper */ struct timespec fh_pre_ctime; /* ctime before oper */ + /* + * pre-op nfsv4 change attr: note must check IS_I_VERSION(inode) + * to find out if it is valid. + */ + u64 fh_pre_change; /* Post-op attributes saved in fh_unlock */ struct kstat fh_post_attr; /* full attrs after operation */ + u64 fh_post_change; /* nfsv4 change; see above */ #endif /* CONFIG_NFSD_V3 */ } svc_fh; @@ -298,6 +304,7 @@ fill_pre_wcc(struct svc_fh *fhp) fhp->fh_pre_mtime = inode->i_mtime; fhp->fh_pre_ctime = inode->i_ctime; fhp->fh_pre_size = inode->i_size; + fhp->fh_pre_change = inode->i_version; fhp->fh_pre_saved = 1; } } diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index f80d6013fdc..d0f050f01ec 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -64,10 +64,13 @@ static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs) struct nfsd4_change_info { u32 atomic; + bool change_supported; u32 before_ctime_sec; u32 before_ctime_nsec; + u64 before_change; u32 after_ctime_sec; u32 after_ctime_nsec; + u64 after_change; }; struct nfsd4_access { @@ -503,10 +506,16 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) { BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved); cinfo->atomic = 1; - cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; - cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; - cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; - cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; + cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); + if (cinfo->change_supported) { + cinfo->before_change = fhp->fh_pre_change; + cinfo->after_change = fhp->fh_post_change; + } else { + cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; + cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; + cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; + cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; + } } int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); -- cgit v1.2.3 From 3cef9ab266a932899e756f7e1ea7a988a97bf3b2 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 23 Feb 2009 21:42:10 -0800 Subject: nfsd4: lookup up callback cred only once Lookup the callback cred once and then use it for all subsequent callbacks. Signed-off-by: J. Bruce Fields --- include/linux/nfsd/state.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 4d61c873fee..8d882a3eb4b 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -97,6 +97,7 @@ struct nfs4_callback { /* RPC client info */ atomic_t cb_set; /* successful CB_NULL call */ struct rpc_clnt * cb_client; + struct rpc_cred * cb_cred; }; /* Maximum number of slots per session. 128 is useful for long haul TCP */ -- cgit v1.2.3 From c237dc0303bcf6f4cc2e0efe4fe4e341c6f34dac Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 29 Apr 2009 19:09:19 -0400 Subject: nfsd4: rename callback struct to cb_conn I want to use the name for a struct that actually does represent a single callback. (Actually, I've never been sure it helps to a separate struct for the callback information. Some day maybe those fields could just be dumped into struct nfs4_client. I don't know.) Signed-off-by: J. Bruce Fields --- include/linux/nfsd/state.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 8d882a3eb4b..563c367a301 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -88,7 +88,7 @@ struct nfs4_delegation { #define dl_fh dl_recall.cbr_fh /* client delegation callback info */ -struct nfs4_callback { +struct nfs4_cb_conn { /* SETCLIENTID info */ u32 cb_addr; unsigned short cb_port; @@ -186,7 +186,7 @@ struct nfs4_client { struct svc_cred cl_cred; /* setclientid principal */ clientid_t cl_clientid; /* generated by server */ nfs4_verifier cl_confirm; /* generated by server */ - struct nfs4_callback cl_callback; /* callback info */ + struct nfs4_cb_conn cl_cb_conn; /* callback info */ atomic_t cl_count; /* ref count */ u32 cl_firststate; /* recovery dir creation */ -- cgit v1.2.3 From b53d40c5070bffde1b2bcaf848412a50d8894794 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 1 May 2009 19:50:00 -0400 Subject: nfsd4: eliminate struct nfs4_cb_recall The nfs4_cb_recall struct is used only in nfs4_delegation, so its pointer to the containing delegation is unnecessary--we could just use container_of(). But there's no real reason to have this a separate struct at all--just move these fields to nfs4_delegation. Signed-off-by: J. Bruce Fields --- include/linux/nfsd/state.h | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 563c367a301..233b60d39b8 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -61,15 +61,6 @@ typedef struct { #define si_stateownerid si_opaque.so_stateownerid #define si_fileid si_opaque.so_fileid - -struct nfs4_cb_recall { - u32 cbr_ident; - int cbr_trunc; - stateid_t cbr_stateid; - struct knfsd_fh cbr_fh; - struct nfs4_delegation *cbr_dp; -}; - struct nfs4_delegation { struct list_head dl_perfile; struct list_head dl_perclnt; @@ -81,12 +72,13 @@ struct nfs4_delegation { struct file *dl_vfs_file; u32 dl_type; time_t dl_time; - struct nfs4_cb_recall dl_recall; +/* For recall: */ + u32 dl_ident; + int dl_trunc; + stateid_t dl_stateid; + struct knfsd_fh dl_fh; }; -#define dl_stateid dl_recall.cbr_stateid -#define dl_fh dl_recall.cbr_fh - /* client delegation callback info */ struct nfs4_cb_conn { /* SETCLIENTID info */ -- cgit v1.2.3 From 6707bd3d420f53ae8f090dac871843f6f43c9980 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 1 May 2009 19:57:46 -0400 Subject: nfsd4: remove unused dl_trunc There's no point in keeping this field around--it's always zero. (Background: the protocol allows you to tell the client that the file is about to be truncated, as an optimization to save the client from writing back dirty pages that will just be discarded. We don't implement this hint. If we do some day, adding this field back in will be the least of the work involved.) Signed-off-by: J. Bruce Fields --- include/linux/nfsd/state.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 233b60d39b8..346b603072c 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -74,7 +74,6 @@ struct nfs4_delegation { time_t dl_time; /* For recall: */ u32 dl_ident; - int dl_trunc; stateid_t dl_stateid; struct knfsd_fh dl_fh; }; -- cgit v1.2.3 From 3aea09dc9106407d8bc18e593fbffda9ad632844 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 1 May 2009 20:11:12 -0400 Subject: nfsd4: track recall retries in nfs4_delegation Move this out of a local variable into the nfs4_delegation object in preparation for making this an async rpc call (at which point we'll need any state like this in a common object that's preserved across function calls). Signed-off-by: J. Bruce Fields --- include/linux/nfsd/state.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 346b603072c..c0c49215ddc 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -76,6 +76,7 @@ struct nfs4_delegation { u32 dl_ident; stateid_t dl_stateid; struct knfsd_fh dl_fh; + int dl_retries; }; /* client delegation callback info */ -- cgit v1.2.3 From fca4217c5bab31019b5247e977673c9fcc385f6b Mon Sep 17 00:00:00 2001 From: Greg Banks Date: Wed, 1 Apr 2009 07:28:13 +1100 Subject: knfsd: reply cache cleanups Make REQHASH() an inline function. Rename hash_list to cache_hash. Fix an obsolete comment. Signed-off-by: Greg Banks Signed-off-by: J. Bruce Fields --- include/linux/nfsd/cache.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h index 5bccaab8105..3a3f58934f5 100644 --- a/include/linux/nfsd/cache.h +++ b/include/linux/nfsd/cache.h @@ -14,8 +14,7 @@ #include /* - * Representation of a reply cache entry. The first two members *must* - * be hash_next and hash_prev. + * Representation of a reply cache entry. */ struct svc_cacherep { struct hlist_node c_hash; -- cgit v1.2.3 From 6c18ba9f5e506b8115b89b1aa7bdc25178f40b0a Mon Sep 17 00:00:00 2001 From: Alexandros Batsakis Date: Tue, 16 Jun 2009 04:19:13 +0300 Subject: nfsd41: move channel attributes from nfsd4_session to a nfsd4_channel_attr struct the change is valid for both the forechannel and the backchannel (currently dummy) Signed-off-by: Alexandros Batsakis Signed-off-by: Benny Halevy Signed-off-by: J. Bruce Fields --- include/linux/nfsd/state.h | 18 +++++++++++++----- include/linux/nfsd/xdr4.h | 11 ----------- 2 files changed, 13 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index c0c49215ddc..105cc100de0 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -115,6 +115,17 @@ struct nfsd4_slot { struct nfsd4_cache_entry sl_cache_entry; }; +struct nfsd4_channel_attrs { + u32 headerpadsz; + u32 maxreq_sz; + u32 maxresp_sz; + u32 maxresp_cached; + u32 maxops; + u32 maxreqs; + u32 nr_rdma_attrs; + u32 rdma_attrs; +}; + struct nfsd4_session { struct kref se_ref; struct list_head se_hash; /* hash by sessionid */ @@ -122,11 +133,8 @@ struct nfsd4_session { u32 se_flags; struct nfs4_client *se_client; /* for expire_client */ struct nfs4_sessionid se_sessionid; - u32 se_fmaxreq_sz; - u32 se_fmaxresp_sz; - u32 se_fmaxresp_cached; - u32 se_fmaxops; - u32 se_fnumslots; + struct nfsd4_channel_attrs se_fchannel; + struct nfsd4_channel_attrs se_bchannel; struct nfsd4_slot se_slots[]; /* forward channel slots */ }; diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index d0f050f01ec..2bacf753506 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -366,17 +366,6 @@ struct nfsd4_exchange_id { int spa_how; }; -struct nfsd4_channel_attrs { - u32 headerpadsz; - u32 maxreq_sz; - u32 maxresp_sz; - u32 maxresp_cached; - u32 maxops; - u32 maxreqs; - u32 nr_rdma_attrs; - u32 rdma_attrs; -}; - struct nfsd4_create_session { clientid_t clientid; struct nfs4_sessionid sessionid; -- cgit v1.2.3 From ab52ae6db035fa425f90146327ab7d2c5d3e5654 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Tue, 16 Jun 2009 04:20:53 +0300 Subject: nfsd41: Backchannel: minorversion support for the back channel Prepare to share backchannel code with NFSv4.1. Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy Signed-off-by: Ricardo Labiaga [nfsd41: use nfsd4_cb_sequence for callback minorversion] Signed-off-by: Benny Halevy Signed-off-by: J. Bruce Fields --- include/linux/nfsd/state.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 105cc100de0..f5a95fd3431 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -85,7 +85,8 @@ struct nfs4_cb_conn { u32 cb_addr; unsigned short cb_port; u32 cb_prog; - u32 cb_ident; + u32 cb_minorversion; + u32 cb_ident; /* minorversion 0 only */ /* RPC client info */ atomic_t cb_set; /* successful CB_NULL call */ struct rpc_clnt * cb_client; -- cgit v1.2.3