5.10.220-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 430/770 lockd: simplify management of network status notifiers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit 5a8a7ff57421b7de3ae72019938ffb5daaee36e7 ]
Now that the network status notifiers use nlmsvc_serv rather then nlmsvc_rqst the management can be simplified.
Notifier unregistration synchronises with any pending notifications so providing we unregister before nlm_serv is freed no further interlock is required.
So we move the unregister call to just before the thread is killed (which destroys the service) and just before the service is destroyed in the failure-path of lockd_up().
Then nlm_ntf_refcnt and nlm_ntf_wq can be removed.
--- fs/lockd/svc.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-)
fs/lockd/svc.c +9 -26
@@ -59,9 +59,6 @@ static struct task_struct *nlmsvc_task;static struct svc_rqst *nlmsvc_rqst;unsigned long nlmsvc_timeout; -static atomic_t nlm_ntf_refcnt =ATOMIC_INIT (0 ); -static DECLARE_WAIT_QUEUE_HEAD (nlm_ntf_wq); -unsigned int lockd_net_id;/*
@@ -303,8 +300,7 @@ static int lockd_inetaddr_event(struct notifier_block *this,struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;struct sockaddr_in sin; -if ((event !=NETDEV_DOWN ) || - !atomic_inc_not_zero (&nlm_ntf_refcnt)) +if (event !=NETDEV_DOWN ) goto out;if (nlmsvc_serv) {
@@ -314,8 +310,6 @@ static int lockd_inetaddr_event(struct notifier_block *this, sin.sin_addr.s_addr = ifa->ifa_local;svc_age_temp_xprts_now (nlmsvc_serv, (struct sockaddr *)&sin); } -atomic_dec (&nlm_ntf_refcnt); -wake_up (&nlm_ntf_wq); out:return NOTIFY_DONE ;
@@ -332,8 +326,7 @@ static int lockd_inet6addr_event(struct notifier_block *this,struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;struct sockaddr_in6 sin6; -if ((event !=NETDEV_DOWN ) || - !atomic_inc_not_zero (&nlm_ntf_refcnt)) +if (event !=NETDEV_DOWN ) goto out;if (nlmsvc_serv) {
@@ -344,8 +337,6 @@ static int lockd_inet6addr_event(struct notifier_block *this, sin6.sin6_scope_id = ifa->idev->dev->ifindex;svc_age_temp_xprts_now (nlmsvc_serv, (struct sockaddr *)&sin6); } -atomic_dec (&nlm_ntf_refcnt); -wake_up (&nlm_ntf_wq); out:return NOTIFY_DONE ;
@@ -362,14 +353,6 @@ static void lockd_unregister_notifiers(void)#if IS_ENABLED (CONFIG_IPV6 )unregister_inet6addr_notifier (&lockd_inet6addr_notifier);#endif -wait_event (nlm_ntf_wq,atomic_read (&nlm_ntf_refcnt) ==0 ); -} - -static void lockd_svc_exit_thread (void ) -{ -atomic_dec (&nlm_ntf_refcnt); -lockd_unregister_notifiers (); -svc_exit_thread (nlmsvc_rqst); }static int lockd_start_svc (struct svc_serv *serv)
@@ -388,11 +371,9 @@ static int lockd_start_svc(struct svc_serv *serv)printk (KERN_WARNING "lockd_up: svc_rqst allocation failed, error=%d\n" , error); -lockd_unregister_notifiers (); goto out_rqst; } -atomic_inc (&nlm_ntf_refcnt);svc_sock_update_bufs (serv); serv->sv_maxconn = nlm_max_connections;
@@ -410,7 +391,7 @@ static int lockd_start_svc(struct svc_serv *serv)return 0 ; out_task: -lockd_svc_exit_thread (); +svc_exit_thread (nlmsvc_rqst); nlmsvc_task =NULL ; out_rqst: nlmsvc_rqst =NULL ;
@@ -477,7 +458,6 @@ int lockd_up(struct net *net, const struct cred *cred) error =lockd_up_net (serv, net, cred);if (error <0 ) { -lockd_unregister_notifiers (); goto err_put; }
@@ -488,8 +468,10 @@ int lockd_up(struct net *net, const struct cred *cred) } nlmsvc_users++; err_put: -if (nlmsvc_users ==0 ) +if (nlmsvc_users ==0 ) { +lockd_unregister_notifiers (); nlmsvc_serv =NULL ; + }svc_put (serv); err_create:mutex_unlock (&nlmsvc_mutex);
@@ -518,13 +500,14 @@ lockd_down(struct net *net)printk (KERN_ERR "lockd_down: no lockd running.\n" );BUG (); } +lockd_unregister_notifiers ();kthread_stop (nlmsvc_task);dprintk ("lockd_down: service stopped\n" ); -lockd_svc_exit_thread (); +svc_exit_thread (nlmsvc_rqst); + nlmsvc_rqst =NULL ;dprintk ("lockd_down: service destroyed\n" ); nlmsvc_serv =NULL ; nlmsvc_task =NULL ; - nlmsvc_rqst =NULL ; out:mutex_unlock (&nlmsvc_mutex); }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 431/770 lockd: move lockd_start_svc() call into lockd_create_svc()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit b73a2972041bee70eb0cbbb25fa77828c63c916b ]
lockd_start_svc() only needs to be called once, just after the svc is created. If the start fails, the svc is discarded too.
It thus makes sense to call lockd_start_svc() from lockd_create_svc(). This allows us to remove the test against nlmsvc_rqst at the start of lockd_start_svc() - it must always be NULL.
lockd_up() only held an extra reference on the svc until a thread was created - then it dropped it. The thread - and thus the extra reference
- will remain until kthread_stop() is called.
Now that the thread is created in lockd_create_svc(), the extra reference can be dropped there. So the 'serv' variable is no longer needed in lockd_up().
--- fs/lockd/svc.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-)
fs/lockd/svc.c +10 -12
@@ -359,9 +359,6 @@ static int lockd_start_svc(struct svc_serv *serv) {int error; -if (nlmsvc_rqst) -return 0 ; -/* * Create the kernel thread and wait for it to start. */
@@ -406,6 +403,7 @@ static const struct svc_serv_ops lockd_sv_ops = {static int lockd_create_svc (void ) {struct svc_serv *serv; +int error;/* * Check whether we're already up and running.
@@ -432,6 +430,13 @@ static int lockd_create_svc(void)printk (KERN_WARNING "lockd_up: create service failed\n" );return -ENOMEM ; } + + error =lockd_start_svc (serv); +/* The thread now holds the only reference */ +svc_put (serv); +if (error <0 ) +return error; + nlmsvc_serv = serv;register_inetaddr_notifier (&lockd_inetaddr_notifier);#if IS_ENABLED (CONFIG_IPV6 )
@@ -446,7 +451,6 @@ static int lockd_create_svc(void)*/ int lockd_up (struct net *net,const struct cred *cred) { -struct svc_serv *serv;int error;mutex_lock (&nlmsvc_mutex);
@@ -454,25 +458,19 @@ int lockd_up(struct net *net, const struct cred *cred) error =lockd_create_svc ();if (error) goto err_create; - serv = nlmsvc_serv; - error =lockd_up_net (serv, net, cred); + error =lockd_up_net (nlmsvc_serv, net, cred);if (error <0 ) { goto err_put; } - error =lockd_start_svc (serv); -if (error <0 ) { -lockd_down_net (serv, net); - goto err_put; - } nlmsvc_users++; err_put:if (nlmsvc_users ==0 ) {lockd_unregister_notifiers (); +kthread_stop (nlmsvc_task); nlmsvc_serv =NULL ; } -svc_put (serv); err_create:mutex_unlock (&nlmsvc_mutex);return error;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 432/770 lockd: move svc_exit_thread() into the thread
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit 6a4e2527a63620a820c4ebf3596b57176da26fb3 ]
The normal place to call svc_exit_thread() is from the thread itself just before it exists.
Do this for lockd.
This means that nlmsvc_rqst is not used out side of lockd_start_svc(), so it can be made local to that function, and renamed to 'rqst'.
--- fs/lockd/svc.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
fs/lockd/svc.c +12 -11
@@ -56,7 +56,6 @@ static DEFINE_MUTEX(nlmsvc_mutex);static unsigned int nlmsvc_users;static struct svc_serv *nlmsvc_serv;static struct task_struct *nlmsvc_task; -static struct svc_rqst *nlmsvc_rqst;unsigned long nlmsvc_timeout;unsigned int lockd_net_id;
@@ -182,6 +181,11 @@ lockd(void *vrqstp)nlm_shutdown_hosts ();cancel_delayed_work_sync (&ln->grace_period_end);locks_end_grace (&ln->lockd_manager); + +dprintk ("lockd_down: service stopped\n" ); + +svc_exit_thread (rqstp); +return 0 ; }
@@ -358,13 +362,14 @@ static void lockd_unregister_notifiers(void)static int lockd_start_svc (struct svc_serv *serv) {int error; +struct svc_rqst *rqst;/* * Create the kernel thread and wait for it to start. */ - nlmsvc_rqst =svc_prepare_thread (serv, &serv->sv_pools[0 ],NUMA_NO_NODE ); -if (IS_ERR (nlmsvc_rqst)) { - error =PTR_ERR (nlmsvc_rqst); + rqst =svc_prepare_thread (serv, &serv->sv_pools[0 ],NUMA_NO_NODE ); +if (IS_ERR (rqst)) { + error =PTR_ERR (rqst);printk (KERN_WARNING "lockd_up: svc_rqst allocation failed, error=%d\n" , error);
@@ -374,24 +379,23 @@ static int lockd_start_svc(struct svc_serv *serv)svc_sock_update_bufs (serv); serv->sv_maxconn = nlm_max_connections; - nlmsvc_task =kthread_create (lockd, nlmsvc_rqst,"%s" , serv->sv_name); + nlmsvc_task =kthread_create (lockd, rqst,"%s" , serv->sv_name);if (IS_ERR (nlmsvc_task)) { error =PTR_ERR (nlmsvc_task);printk (KERN_WARNING "lockd_up: kthread_run failed, error=%d\n" , error); goto out_task; } - nlmsvc_rqst->rq_task = nlmsvc_task; + rqst->rq_task = nlmsvc_task;wake_up_process (nlmsvc_task);dprintk ("lockd_up: service started\n" );return 0 ; out_task: -svc_exit_thread (nlmsvc_rqst); +svc_exit_thread (rqst); nlmsvc_task =NULL ; out_rqst: - nlmsvc_rqst =NULL ;return error; }
@@ -500,9 +504,6 @@ lockd_down(struct net *net) }lockd_unregister_notifiers ();kthread_stop (nlmsvc_task); -dprintk ("lockd_down: service stopped\n" ); -svc_exit_thread (nlmsvc_rqst); - nlmsvc_rqst =NULL ;dprintk ("lockd_down: service destroyed\n" ); nlmsvc_serv =NULL ; nlmsvc_task =NULL ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 433/770 lockd: introduce lockd_put()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit 865b674069e05e5779fcf8cf7a166d2acb7e930b ]
There is some cleanup that is duplicated in lockd_down() and the failure path of lockd_up().
Factor these out into a new lockd_put() and call it from both places.
lockd_put() does *not* take the mutex - that must be held by the caller. It decrements nlmsvc_users and if that reaches zero, it cleans up.
--- fs/lockd/svc.c | 64 +++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 37 deletions(-)
fs/lockd/svc.c +27 -37
@@ -351,14 +351,6 @@ static struct notifier_block lockd_inet6addr_notifier = { };#endif -static void lockd_unregister_notifiers (void ) -{ -unregister_inetaddr_notifier (&lockd_inetaddr_notifier); -#if IS_ENABLED (CONFIG_IPV6 ) -unregister_inet6addr_notifier (&lockd_inet6addr_notifier); -#endif -} -static int lockd_start_svc (struct svc_serv *serv) {int error;
@@ -450,6 +442,27 @@ static int lockd_create_svc(void)return 0 ; } +static void lockd_put (void ) +{ +if (WARN (nlmsvc_users <=0 ,"lockd_down: no users!\n" )) +return ; +if (--nlmsvc_users) +return ; + +unregister_inetaddr_notifier (&lockd_inetaddr_notifier); +#if IS_ENABLED (CONFIG_IPV6 ) +unregister_inet6addr_notifier (&lockd_inet6addr_notifier); +#endif + +if (nlmsvc_task) { +kthread_stop (nlmsvc_task); +dprintk ("lockd_down: service stopped\n" ); + nlmsvc_task =NULL ; + } + nlmsvc_serv =NULL ; +dprintk ("lockd_down: service destroyed\n" ); +} +/* * Bring up the lockd process if it's not already up. */
@@ -461,21 +474,16 @@ int lockd_up(struct net *net, const struct cred *cred) error =lockd_create_svc ();if (error) - goto err_create; + goto err; + nlmsvc_users++; error =lockd_up_net (nlmsvc_serv, net, cred);if (error <0 ) { - goto err_put; +lockd_put (); + goto err; } - nlmsvc_users++; -err_put: -if (nlmsvc_users ==0 ) { -lockd_unregister_notifiers (); -kthread_stop (nlmsvc_task); - nlmsvc_serv =NULL ; - } -err_create: +err:mutex_unlock (&nlmsvc_mutex);return error; }
@@ -489,25 +497,7 @@ lockd_down(struct net *net) {mutex_lock (&nlmsvc_mutex);lockd_down_net (nlmsvc_serv, net); -if (nlmsvc_users) { -if (--nlmsvc_users) - goto out; - }else { -printk (KERN_ERR "lockd_down: no users! task=%p\n" , - nlmsvc_task); -BUG (); - } - -if (!nlmsvc_task) { -printk (KERN_ERR "lockd_down: no lockd running.\n" ); -BUG (); - } -lockd_unregister_notifiers (); -kthread_stop (nlmsvc_task); -dprintk ("lockd_down: service destroyed\n" ); - nlmsvc_serv =NULL ; - nlmsvc_task =NULL ; -out: +lockd_put ();mutex_unlock (&nlmsvc_mutex); }EXPORT_SYMBOL_GPL (lockd_down);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 434/770 lockd: rename lockd_create_svc() to lockd_get()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit ecd3ad68d2c6d3ae178a63a2d9a02c392904fd36 ]
lockd_create_svc() already does an svc_get() if the service already exists, so it is more like a "get" than a "create".
So:
- Move the increment of nlmsvc_users into the function as well
- rename to lockd_get().
It is now the inverse of lockd_put().
--- fs/lockd/svc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
fs/lockd/svc.c +4 -6
@@ -396,16 +396,14 @@ static const struct svc_serv_ops lockd_sv_ops = { .svo_enqueue_xprt = svc_xprt_do_enqueue, }; -static int lockd_create_svc (void ) +static int lockd_get (void ) {struct svc_serv *serv;int error; -/* -* Check whether we're already up and running. -*/ if (nlmsvc_serv) {svc_get (nlmsvc_serv); + nlmsvc_users++;return 0 ; }
@@ -439,6 +437,7 @@ static int lockd_create_svc(void)register_inet6addr_notifier (&lockd_inet6addr_notifier);#endif dprintk ("lockd_up: service created\n" ); + nlmsvc_users++;return 0 ; }
@@ -472,10 +471,9 @@ int lockd_up(struct net *net, const struct cred *cred)mutex_lock (&nlmsvc_mutex); - error =lockd_create_svc (); + error =lockd_get ();if (error) goto err; - nlmsvc_users++; error =lockd_up_net (nlmsvc_serv, net, cred);if (error <0 ) {
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 435/770 SUNRPC: move the pool_map definitions (back) into svc.c
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit cf0e124e0a489944d08fcc3c694d2b234d2cc658 ]
These definitions are not used outside of svc.c, and there is no evidence that they ever have been. So move them into svc.c and make the declarations 'static'.
--- include/linux/sunrpc/svc.h | 25 ------------------------- net/sunrpc/svc.c | 31 +++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 31 deletions(-)
include/linux/sunrpc/svc.h +0 -25
@@ -497,29 +497,6 @@ struct svc_procedure {const char * pc_name;/* for display */ }; -/* -* Mode for mapping cpus to pools. -*/ -enum { -SVC_POOL_AUTO =-1 ,/* choose one of the others */ -SVC_POOL_GLOBAL ,/* no mapping, just a single global pool -* (legacy & UP mode) */ -SVC_POOL_PERCPU ,/* one pool per cpu */ -SVC_POOL_PERNODE /* one pool per numa node */ -}; - -struct svc_pool_map { -int count;/* How many svc_servs use us */ -int mode;/* Note: int not enum to avoid -* warnings about "enumeration value -* not handled in switch" */ -unsigned int npools; -unsigned int *pool_to;/* maps pool id to cpu or node */ -unsigned int *to_pool;/* maps cpu or node to pool id */ -}; - -extern struct svc_pool_map svc_pool_map; -/* * Function prototypes. */
@@ -536,8 +513,6 @@ void svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page);void svc_rqst_free (struct svc_rqst *);void svc_exit_thread (struct svc_rqst *); -unsigned int svc_pool_map_get (void ); -void svc_pool_map_put (void );struct svc_serv *svc_create_pooled (struct svc_program *,unsigned int ,const struct svc_serv_ops *);int svc_set_num_threads (struct svc_serv *,struct svc_pool *,int );
net/sunrpc/svc.c +25 -6
@@ -39,14 +39,35 @@ static void svc_unregister(const struct svc_serv *serv, struct net *net);#define SVC_POOL_DEFAULT SVC_POOL_GLOBAL +/* +* Mode for mapping cpus to pools. +*/ +enum { +SVC_POOL_AUTO =-1 ,/* choose one of the others */ +SVC_POOL_GLOBAL ,/* no mapping, just a single global pool +* (legacy & UP mode) */ +SVC_POOL_PERCPU ,/* one pool per cpu */ +SVC_POOL_PERNODE /* one pool per numa node */ +}; +/* * Structure for mapping cpus to pools and vice versa. * Setup once during sunrpc initialisation. */ -struct svc_pool_map svc_pool_map = { + +struct svc_pool_map { +int count;/* How many svc_servs use us */ +int mode;/* Note: int not enum to avoid +* warnings about "enumeration value +* not handled in switch" */ +unsigned int npools; +unsigned int *pool_to;/* maps pool id to cpu or node */ +unsigned int *to_pool;/* maps cpu or node to pool id */ +}; + +static struct svc_pool_map svc_pool_map = { .mode =SVC_POOL_DEFAULT }; -EXPORT_SYMBOL_GPL (svc_pool_map);static DEFINE_MUTEX (svc_pool_map_mutex);/* protects svc_pool_map.count only */
@@ -220,7 +241,7 @@ svc_pool_map_init_pernode(struct svc_pool_map *m)* vice versa). Initialise the map if we're the first user. * Returns the number of pools. */ -unsigned int +static unsigned int svc_pool_map_get (void ) {struct svc_pool_map *m = &svc_pool_map;
@@ -255,7 +276,6 @@ svc_pool_map_get(void)mutex_unlock (&svc_pool_map_mutex);return m->npools; } -EXPORT_SYMBOL_GPL (svc_pool_map_get);/* * Drop a reference to the global map of cpus to pools.
@@ -264,7 +284,7 @@ EXPORT_SYMBOL_GPL(svc_pool_map_get);* mode using the pool_mode module option without * rebooting or re-loading sunrpc.ko. */ -void +static void svc_pool_map_put (void ) {struct svc_pool_map *m = &svc_pool_map;
@@ -281,7 +301,6 @@ svc_pool_map_put(void)mutex_unlock (&svc_pool_map_mutex); } -EXPORT_SYMBOL_GPL (svc_pool_map_put);static int svc_pool_map_get_node (unsigned int pidx) {
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 436/770 SUNRPC: always treat sv_nrpools==1 as "not pooled"
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit 93aa619eb0b42eec2f3a9b4d9db41f5095390aec ]
Currently 'pooled' services hold a reference on the pool_map, and 'unpooled' services do not.svc_destroy() uses the presence of ->svo_function (via svc_serv_is_pooled()) to determine if the reference should be dropped. There is no direct correlation between being pooled and the use of svo_function, though in practice, lockd is the only non-pooled service, and the only one not to use svo_function.
This is untidy and would cause problems if we changed lockd to use svc_set_num_threads(), which requires the use of ->svo_function.
So change the test for "is the service pooled" to "is sv_nrpools > 1".
This means that when svc_pool_map_get() returns 1, it must NOT take a reference to the pool.
We discard svc_serv_is_pooled(), and test sv_nrpools directly.
--- net/sunrpc/svc.c | 54 ++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 25 deletions(-)
net/sunrpc/svc.c +29 -25
@@ -35,8 +35,6 @@static void svc_unregister (const struct svc_serv *serv,struct net *net); -#define svc_serv_is_pooled (serv) ((serv)->sv_ops->svo_function) -#define SVC_POOL_DEFAULT SVC_POOL_GLOBAL/*
@@ -238,8 +236,10 @@ svc_pool_map_init_pernode(struct svc_pool_map *m)/* * Add a reference to the global map of cpus to pools (and -* vice versa). Initialise the map if we're the first user. -* Returns the number of pools. +* vice versa) if pools are in use. +* Initialise the map if we're the first user. +* Returns the number of pools. If this is '1', no reference +* was taken. */ static unsigned int svc_pool_map_get (void )
@@ -251,6 +251,7 @@ svc_pool_map_get(void)if (m->count++) {mutex_unlock (&svc_pool_map_mutex); +WARN_ON_ONCE (m->npools <=1 );return m->npools; }
@@ -266,29 +267,36 @@ svc_pool_map_get(void)break ; } -if (npools <0 ) { +if (npools <=0 ) {/* default, or memory allocation failure */ npools =1 ; m->mode =SVC_POOL_GLOBAL ; } m->npools = npools; +if (npools ==1 ) +/* service is unpooled, so doesn't hold a reference */ + m->count--; +mutex_unlock (&svc_pool_map_mutex); -return m->npools; +return npools; }/* -* Drop a reference to the global map of cpus to pools. +* Drop a reference to the global map of cpus to pools, if +* pools were in use, i.e. if npools > 1. * When the last reference is dropped, the map data is * freed; this allows the sysadmin to change the pool * mode using the pool_mode module option without * rebooting or re-loading sunrpc.ko. */ static void -svc_pool_map_put (void ) +svc_pool_map_put (int npools) {struct svc_pool_map *m = &svc_pool_map; +if (npools <=1 ) +return ;mutex_lock (&svc_pool_map_mutex);if (!--m->count) {
@@ -357,21 +365,18 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)struct svc_pool_map *m = &svc_pool_map;unsigned int pidx =0 ; -/* -* An uninitialised map happens in a pure client when -* lockd is brought up, so silently treat it the -* same as SVC_POOL_GLOBAL. -*/ -if (svc_serv_is_pooled (serv)) { -switch (m->mode) { -case SVC_POOL_PERCPU : - pidx = m->to_pool[cpu]; -break ; -case SVC_POOL_PERNODE : - pidx = m->to_pool[cpu_to_node (cpu)]; -break ; - } +if (serv->sv_nrpools <=1 ) +return serv->sv_pools; + +switch (m->mode) { +case SVC_POOL_PERCPU : + pidx = m->to_pool[cpu]; +break ; +case SVC_POOL_PERNODE : + pidx = m->to_pool[cpu_to_node (cpu)]; +break ; } +return &serv->sv_pools[pidx % serv->sv_nrpools]; }
@@ -524,7 +529,7 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, goto out_err;return serv; out_err: -svc_pool_map_put (); +svc_pool_map_put (npools);return NULL ; }EXPORT_SYMBOL_GPL (svc_create_pooled);
@@ -559,8 +564,7 @@ svc_destroy(struct kref *ref)cache_clean_deferred (serv); -if (svc_serv_is_pooled (serv)) -svc_pool_map_put (); +svc_pool_map_put (serv->sv_nrpools);kfree (serv->sv_pools);kfree (serv);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 437/770 lockd: use svc_set_num_threads() for thread start and stop
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit 6b044fbaab02292fedb17565dbb3f2528083b169 ]
svc_set_num_threads() does everything that lockd_start_svc() does, except set sv_maxconn. It also (when passed 0) finds the threads and stops them with kthread_stop().
So move the setting for sv_maxconn, and use svc_set_num_thread()
We now don't need nlmsvc_task.
Now that we use svc_set_num_threads() it makes sense to set svo_module. This request that the thread exists with module_put_and_exit(). Also fix the documentation for svo_module to make this explicit.
svc_prepare_thread is now only used where it is defined, so it can be made static.
--- fs/lockd/svc.c | 58 ++++++-------------------------------- include/linux/sunrpc/svc.h | 6 ++-- net/sunrpc/svc.c | 3 +- 3 files changed, 12 insertions(+), 55 deletions(-)
fs/lockd/svc.c +8 -50
@@ -55,7 +55,6 @@ EXPORT_SYMBOL_GPL(nlmsvc_ops);static DEFINE_MUTEX (nlmsvc_mutex);static unsigned int nlmsvc_users;static struct svc_serv *nlmsvc_serv; -static struct task_struct *nlmsvc_task;unsigned long nlmsvc_timeout;unsigned int lockd_net_id;
@@ -186,7 +185,7 @@ lockd(void *vrqstp)svc_exit_thread (rqstp); -return 0 ; +module_put_and_kthread_exit (0 ); } static int create_lockd_listener(struct svc_serv *serv, const char *name,
@@ -292,8 +291,8 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) __func__, net->ns.inum); } }else { -pr_err ("%s: no users! task=%p, net=%x\n" , - __func__, nlmsvc_task, net->ns.inum); +pr_err ("%s: no users! net=%x\n" , + __func__, net->ns.inum);BUG (); } }
@@ -351,49 +350,11 @@ static struct notifier_block lockd_inet6addr_notifier = { };#endif -static int lockd_start_svc (struct svc_serv *serv) -{ -int error; -struct svc_rqst *rqst; - -/* -* Create the kernel thread and wait for it to start. -*/ - rqst =svc_prepare_thread (serv, &serv->sv_pools[0 ],NUMA_NO_NODE ); -if (IS_ERR (rqst)) { - error =PTR_ERR (rqst); -printk (KERN_WARNING -"lockd_up: svc_rqst allocation failed, error=%d\n" , - error); - goto out_rqst; - } - -svc_sock_update_bufs (serv); - serv->sv_maxconn = nlm_max_connections; - - nlmsvc_task =kthread_create (lockd, rqst,"%s" , serv->sv_name); -if (IS_ERR (nlmsvc_task)) { - error =PTR_ERR (nlmsvc_task); -printk (KERN_WARNING -"lockd_up: kthread_run failed, error=%d\n" , error); - goto out_task; - } - rqst->rq_task = nlmsvc_task; -wake_up_process (nlmsvc_task); - -dprintk ("lockd_up: service started\n" ); -return 0 ; - -out_task: -svc_exit_thread (rqst); - nlmsvc_task =NULL ; -out_rqst: -return error; -} -static const struct svc_serv_ops lockd_sv_ops = { .svo_shutdown = svc_rpcb_cleanup, + .svo_function = lockd, .svo_enqueue_xprt = svc_xprt_do_enqueue, + .svo_module =THIS_MODULE , };static int lockd_get (void )
@@ -425,7 +386,8 @@ static int lockd_get(void)return -ENOMEM ; } - error =lockd_start_svc (serv); + serv->sv_maxconn = nlm_max_connections; + error =svc_set_num_threads (serv,NULL ,1 );/* The thread now holds the only reference */ svc_put (serv);if (error <0 )
@@ -453,11 +415,7 @@ static void lockd_put(void)unregister_inet6addr_notifier (&lockd_inet6addr_notifier);#endif -if (nlmsvc_task) { -kthread_stop (nlmsvc_task); -dprintk ("lockd_down: service stopped\n" ); - nlmsvc_task =NULL ; - } +svc_set_num_threads (nlmsvc_serv,NULL ,0 ); nlmsvc_serv =NULL ;dprintk ("lockd_down: service destroyed\n" ); }
include/linux/sunrpc/svc.h +3 -3
@@ -64,7 +64,9 @@ struct svc_serv_ops {/* queue up a transport for servicing */ void (*svo_enqueue_xprt)(struct svc_xprt *); -/* optional module to count when adding threads (pooled svcs only) */ +/* optional module to count when adding threads. +* Thread function must call module_put_and_kthread_exit() to exit. +*/ struct module *svo_module; };
@@ -507,8 +509,6 @@ struct svc_serv *svc_create(struct svc_program *, unsigned int, const struct svc_serv_ops *);struct svc_rqst *svc_rqst_alloc (struct svc_serv *serv,struct svc_pool *pool,int node); -struct svc_rqst *svc_prepare_thread (struct svc_serv *serv, -struct svc_pool *pool,int node);void svc_rqst_replace_page (struct svc_rqst *rqstp,struct page *page);void svc_rqst_free (struct svc_rqst *);
net/sunrpc/svc.c +1 -2
@@ -650,7 +650,7 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node) }EXPORT_SYMBOL_GPL (svc_rqst_alloc); -struct svc_rqst * +static struct svc_rqst *svc_prepare_thread (struct svc_serv *serv,struct svc_pool *pool,int node) {struct svc_rqst *rqstp;
@@ -670,7 +670,6 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)spin_unlock_bh (&pool->sp_lock);return rqstp; } -EXPORT_SYMBOL_GPL (svc_prepare_thread);/* * Choose a pool in which to create a new thread, for svc_set_num_threads
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 438/770 NFS: switch the callback service back to non-pooled.
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit 23a1a573c61ccb5e7829c1f5472d3e025293a031 ]
Now that thread management is consistent there is no need for nfs-callback to use svc_create_pooled() as introduced in Commit df807fffaabd ("NFSv4.x/callback: Create the callback service through svc_create_pooled"). So switch back to svc_create().
If service pools were configured, but the number of threads were left at '1', nfs callback may not work reliably when svc_create_pooled() is used.
--- fs/nfs/callback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfs/callback.c +1 -1
@@ -286,7 +286,7 @@ static struct svc_serv *nfs_callback_create_svc(int minorversion)printk (KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n" , cb_info->users); - serv =svc_create_pooled (&nfs4_callback_program,NFS4_CALLBACK_BUFSIZE , sv_ops); + serv =svc_create (&nfs4_callback_program,NFS4_CALLBACK_BUFSIZE , sv_ops);if (!serv) {printk (KERN_ERR "nfs_callback_create_svc: create service failed\n" );return ERR_PTR (-ENOMEM );
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 439/770 NFSD: Remove be32_to_cpu() from DRC hash function
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 7578b2f628db27281d3165af0aa862311883a858 ]
Commit 7142b98d9fd7 ("nfsd: Clean up drc cache in preparation for global spinlock elimination"), billed as a clean-up, added be32_to_cpu() to the DRC hash function without explanation. That commit removed two comments that state that byte-swapping in the hash function is unnecessary without explaining whether there was a need for that change.
On some Intel CPUs, the swab32 instruction is known to cause a CPU pipeline stall. be32_to_cpu() does not add extra randomness, since the hash multiplication is done /before/ shifting to the high-order bits of the result.
As a micro-optimization, remove the unnecessary transform from the DRC hash function.
--- fs/nfsd/nfscache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfscache.c +1 -1
@@ -87,7 +87,7 @@ nfsd_hashsize(unsigned int limit)static u32 nfsd_cache_hash (__be32 xid,struct nfsd_net *nn) { -return hash_32 (be32_to_cpu (xid), nn->maskbits); +return hash_32 ((__force u32 )xid, nn->maskbits); } static struct svc_cacherep *
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 440/770 NFSD: Fix inconsistent indenting
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiapeng Chong <[email protected]>
[ Upstream commit 1e37d0e5bda45881eea1bec4b812def72c7d4aea ]
Eliminate the follow smatch warning:
fs/nfsd/nfs4xdr.c:4766 nfsd4_encode_read_plus_hole() warn: inconsistent indenting.
--- fs/nfsd/nfs4xdr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/nfsd/nfs4xdr.c +2 -2
@@ -4812,8 +4812,8 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp,return nfserr_resource; *p++ =htonl (NFS4_CONTENT_HOLE ); - p =xdr_encode_hyper (p, read->rd_offset); - p =xdr_encode_hyper (p, count); + p =xdr_encode_hyper (p, read->rd_offset); + p =xdr_encode_hyper (p, count); *eof = (read->rd_offset + count) >= f_size; *maxcount = min_t(unsigned long, count, *maxcount);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 441/770 NFSD: simplify per-net file cache management
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
[ Upstream commit 1463b38e7cf34d4cc60f41daff459ad807b2e408 ]
We currently have a 'laundrette' for closing cached files - a different work-item for each network-namespace.
These 'laundrettes' (aka struct nfsd_fcache_disposal) are currently on a list, and are freed using rcu.
The list is not necessary as we have a per-namespace structure (struct nfsd_net) which can hold a link to the nfsd_fcache_disposal. The use of kfree_rcu is also unnecessary as the cache is cleaned of all files associated with a given namespace, and no new files can be added, before the nfsd_fcache_disposal is freed.
So add a '->fcache_disposal' link to nfsd_net, and discard the list management and rcu usage.
--- fs/nfsd/filecache.c | 76 +++++++++------------------------------------ fs/nfsd/netns.h | 2 ++ 2 files changed, 17 insertions(+), 61 deletions(-)
fs/nfsd/filecache.c +15 -61
@@ -44,12 +44,9 @@ struct nfsd_fcache_bucket { static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);struct nfsd_fcache_disposal { -struct list_head list;struct work_struct work; -struct net *net;spinlock_t lock;struct list_head freeme; -struct rcu_head rcu; };static struct workqueue_struct *nfsd_filecache_wq__read_mostly ;
@@ -62,8 +59,6 @@ static long nfsd_file_lru_flags;static struct fsnotify_group *nfsd_file_fsnotify_group;static atomic_long_t nfsd_filecache_count;static struct delayed_work nfsd_filecache_laundrette; -static DEFINE_SPINLOCK (laundrette_lock); -static LIST_HEAD (laundrettes);static void nfsd_file_gc (void );
@@ -366,19 +361,13 @@ nfsd_file_list_remove_disposal(struct list_head *dst,static void nfsd_file_list_add_disposal (struct list_head *files,struct net *net) { -struct nfsd_fcache_disposal *l; +struct nfsd_net *nn =net_generic (net, nfsd_net_id); +struct nfsd_fcache_disposal *l = nn->fcache_disposal; -rcu_read_lock (); -list_for_each_entry_rcu (l, &laundrettes, list) { -if (l->net == net) { -spin_lock (&l->lock); -list_splice_tail_init (files, &l->freeme); -spin_unlock (&l->lock); -queue_work (nfsd_filecache_wq, &l->work); -break ; - } - } -rcu_read_unlock (); +spin_lock (&l->lock); +list_splice_tail_init (files, &l->freeme); +spin_unlock (&l->lock); +queue_work (nfsd_filecache_wq, &l->work); } static void
@@ -754,7 +743,7 @@ nfsd_file_cache_purge(struct net *net) }static struct nfsd_fcache_disposal * -nfsd_alloc_fcache_disposal (struct net *net) +nfsd_alloc_fcache_disposal (void ) {struct nfsd_fcache_disposal *l;
@@ -762,7 +751,6 @@ nfsd_alloc_fcache_disposal(struct net *net)if (!l)return NULL ;INIT_WORK (&l->work, nfsd_file_delayed_close); - l->net = net;spin_lock_init (&l->lock);INIT_LIST_HEAD (&l->freeme);return l;
@@ -771,61 +759,27 @@ nfsd_alloc_fcache_disposal(struct net *net)static void nfsd_free_fcache_disposal (struct nfsd_fcache_disposal *l) { -rcu_assign_pointer (l->net,NULL );cancel_work_sync (&l->work);nfsd_file_dispose_list (&l->freeme); -kfree_rcu (l, rcu); -} - -static void -nfsd_add_fcache_disposal (struct nfsd_fcache_disposal *l) -{ -spin_lock (&laundrette_lock); -list_add_tail_rcu (&l->list, &laundrettes); -spin_unlock (&laundrette_lock); -} - -static void -nfsd_del_fcache_disposal (struct nfsd_fcache_disposal *l) -{ -spin_lock (&laundrette_lock); -list_del_rcu (&l->list); -spin_unlock (&laundrette_lock); -} - -static int -nfsd_alloc_fcache_disposal_net (struct net *net) -{ -struct nfsd_fcache_disposal *l; - - l =nfsd_alloc_fcache_disposal (net); -if (!l) -return -ENOMEM ; -nfsd_add_fcache_disposal (l); -return 0 ; +kfree (l); }static void nfsd_free_fcache_disposal_net (struct net *net) { -struct nfsd_fcache_disposal *l; +struct nfsd_net *nn =net_generic (net, nfsd_net_id); +struct nfsd_fcache_disposal *l = nn->fcache_disposal; -rcu_read_lock (); -list_for_each_entry_rcu (l, &laundrettes, list) { -if (l->net != net) -continue ; -nfsd_del_fcache_disposal (l); -rcu_read_unlock (); -nfsd_free_fcache_disposal (l); -return ; - } -rcu_read_unlock (); +nfsd_free_fcache_disposal (l); }int nfsd_file_cache_start_net (struct net *net) { -return nfsd_alloc_fcache_disposal_net (net); +struct nfsd_net *nn =net_generic (net, nfsd_net_id); + + nn->fcache_disposal =nfsd_alloc_fcache_disposal (); +return nn->fcache_disposal ?0 : -ENOMEM ; }void
fs/nfsd/netns.h +2 -0
@@ -185,6 +185,8 @@ struct nfsd_net {/* utsname taken from the process that starts the server */ char nfsd_name[UNX_MAXNODENAME +1 ]; + +struct nfsd_fcache_disposal *fcache_disposal; };/* Simple check to find out if a given net was properly initialized */
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 442/770 NFSD: Combine XDR error tracepoints
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 70e94d757b3e1f46486d573729d84c8955c81dce ]
Clean up: The garbage_args and cant_encode tracepoints report the same information as each other, so combine them into a single tracepoint class to reduce code duplication and slightly reduce the size of trace.o.
--- fs/nfsd/trace.h | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-)
fs/nfsd/trace.h +7 -21
@@ -46,7 +46,7 @@ rqstp->rq_xprt->xpt_remotelen); \ }while (0 ); -TRACE_EVENT(nfsd_garbage_args_err, +DECLARE_EVENT_CLASS(nfsd_xdr_err_class, TP_PROTO( const struct svc_rqst *rqstp ),
@@ -68,27 +68,13 @@ TRACE_EVENT(nfsd_garbage_args_err, ) ); -TRACE_EVENT (nfsd_cant_encode_err, -TP_PROTO ( - const struct svc_rqst *rqstp - ), -TP_ARGS (rqstp), -TP_STRUCT__entry ( - NFSD_TRACE_PROC_ARG_FIELDS +#define DEFINE_NFSD_XDR_ERR_EVENT (name) \ +DEFINE_EVENT(nfsd_xdr_err_class, nfsd_##name##_err, \ + TP_PROTO(const struct svc_rqst *rqstp), \ + TP_ARGS(rqstp)) - __field(u32, vers) -__field (u32, proc) - ), -TP_fast_assign ( -NFSD_TRACE_PROC_ARG_ASSIGNMENTS - - __entry->vers = rqstp->rq_vers; - __entry->proc = rqstp->rq_proc; - ), -TP_printk ("xid=0x%08x vers=%u proc=%u" , - __entry->xid, __entry->vers, __entry->proc - ) -); +DEFINE_NFSD_XDR_ERR_EVENT (garbage_args); +DEFINE_NFSD_XDR_ERR_EVENT (cant_encode);#define show_nfsd_may_flags (x) \ __print_flags(x, "|", \
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 443/770 nfsd: improve stateid access bitmask documentation
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: J. Bruce Fields <[email protected]>
[ Upstream commit 3dcd1d8aab00c5d3a0a3725253c86440b1a0f5a7 ]
The use of the bitmaps is confusing. Add a cross-reference to make it easier to find the existing comment. Add an updated reference with URL to make it quicker to look up. And a bit more editorializing about the value of this.
--- fs/nfsd/nfs4state.c | 14 ++++++++++---- fs/nfsd/state.h | 4 ++++ 2 files changed, 14 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +10 -4
@@ -360,11 +360,13 @@ static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = {* st_{access,deny}_bmap field of the stateid, in order to track not * only what share bits are currently in force, but also what * combinations of share bits previous opens have used. This allows us -* to enforce the recommendation of rfc 3530 14.2.19 that the server -* return an error if the client attempt to downgrade to a combination -* of share bits not explicable by closing some of its previous opens. +* to enforce the recommendation in +* https://datatracker.ietf.org/doc/html/rfc7530#section-16.19.4 that +* the server return an error if the client attempt to downgrade to a +* combination of share bits not explicable by closing some of its +* previous opens. * -* XXX: This enforcement is actually incomplete, since we don't keep +* This enforcement is arguably incomplete, since we don't keep * track of access/deny bit combinations; so, e.g., we allow: * * OPEN allow read, deny write
@@ -372,6 +374,10 @@ static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = {* DOWNGRADE allow read, deny none * * which we should reject. +* +* But you could also argue that our current code is already overkill, +* since it only exists to return NFS4ERR_INVAL on incorrect client +* behavior. */ static unsigned int bmap_to_share_mode (unsigned long bmap)
fs/nfsd/state.h +4 -0
@@ -568,6 +568,10 @@ struct nfs4_ol_stateid {struct list_head st_locks;struct nfs4_stateowner *st_stateowner;struct nfs4_clnt_odstate *st_clnt_odstate; +/* +* These bitmasks use 3 separate bits for READ, ALLOW, and BOTH; see the +* comment above bmap_to_share_mode() for explanation: +*/ unsigned char st_access_bmap;unsigned char st_deny_bmap;struct nfs4_ol_stateid *st_openstp;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 444/770 NFSD: De-duplicate nfsd4_decode_bitmap4()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit cd2e999c7c394ae916d8be741418b3c6c1dddea8 ]
Clean up. Trond points out that xdr_stream_decode_uint32_array() does the same thing as nfsd4_decode_bitmap4().
--- fs/nfsd/nfs4xdr.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-)
fs/nfsd/nfs4xdr.c +3 -14
@@ -277,21 +277,10 @@ nfsd4_decode_verifier4(struct nfsd4_compoundargs *argp, nfs4_verifier *verf)static __be32 nfsd4_decode_bitmap4 (struct nfsd4_compoundargs *argp,u32 *bmval,u32 bmlen) { -u32 i, count; -__be32 *p; - -if (xdr_stream_decode_u32 (argp->xdr, &count) <0 ) -return nfserr_bad_xdr; -/* request sanity */ -if (count >1000 ) -return nfserr_bad_xdr; - p =xdr_inline_decode (argp->xdr, count <<2 ); -if (!p) -return nfserr_bad_xdr; -for (i =0 ; i < bmlen; i++) - bmval[i] = (i < count) ?be32_to_cpup (p++) :0 ; +ssize_t status; -return nfs_ok; + status =xdr_stream_decode_uint32_array (argp->xdr, bmval, bmlen); +return status == -EBADMSG ? nfserr_bad_xdr : nfs_ok; } static __be32
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 445/770 nfs: block notification on fs with its own ->lock
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: J. Bruce Fields <[email protected]>
[ Upstream commit 40595cdc93edf4110c0f0c0b06f8d82008f23929 ]
NFSv4.1 supports an optional lock notification feature which notifies the client when a lock comes available. (Normally NFSv4 clients just poll for locks if necessary.) To make that work, we need to request a blocking lock from the filesystem.
We turned that off for NFS in commit f657f8eef3ff ("nfs: don't atempt blocking locks on nfs reexports") [sic] because it actually blocks the nfsd thread while waiting for the lock.
Thanks to Vasily Averin for pointing out that NFS isn't the only filesystem with that problem.
Any filesystem that leaves ->lock NULL will use posix_lock_file(), which does the right thing. Simplest is just to assume that any filesystem that defines its own ->lock is not safe to request a blocking lock from.
So, this patch mostly reverts commit f657f8eef3ff ("nfs: don't atempt blocking locks on nfs reexports") [sic] and commit b840be2f00c0 ("lockd:
don't attempt blocking locks on nfs reexports"), and instead uses a check of ->lock (Vasily's suggestion) to decide whether to support blocking lock notifications on a given filesystem. Also add a little documentation.
Perhaps someday we could add back an export flag later to allow filesystems with "good" ->lock methods to support blocking lock notifications.
--- fs/lockd/svclock.c | 6 ++++-- fs/nfs/export.c | 2 +- fs/nfsd/nfs4state.c | 18 ++++++++++++------ include/linux/exportfs.h | 2 -- include/linux/lockd/lockd.h | 9 +++++++-- 5 files changed, 24 insertions(+), 13 deletions(-)
fs/lockd/svclock.c +4 -2
@@ -470,8 +470,10 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_host *host, struct nlm_lock *lock, int wait, struct nlm_cookie *cookie, int reclaim) { - struct nlm_block *block = NULL; +#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) struct inode *inode = nlmsvc_file_inode(file); +#endif +struct nlm_block *block =NULL ;int error;int mode;int async_block =0 ;
@@ -484,7 +486,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, (long long )lock->fl.fl_end, wait); -if (inode->i_sb->s_export_op->flags &EXPORT_OP_SYNC_LOCKS ) { +if (nlmsvc_file_file (file)->f_op->lock) { async_block = wait; wait =0 ; }
fs/nfs/export.c +1 -1
@@ -184,5 +184,5 @@ const struct export_operations nfs_export_ops = { .fetch_iversion = nfs_fetch_iversion, .flags =EXPORT_OP_NOWCC |EXPORT_OP_NOSUBTREECHK |EXPORT_OP_CLOSE_BEFORE_UNLINK |EXPORT_OP_REMOTE_FS | - EXPORT_OP_NOATOMIC_ATTR|EXPORT_OP_SYNC_LOCKS, + EXPORT_OP_NOATOMIC_ATTR, };
fs/nfsd/nfs4state.c +12 -6
@@ -6884,7 +6884,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,struct nfsd4_blocked_lock *nbl =NULL ;struct file_lock *file_lock =NULL ;struct file_lock *conflock =NULL ; -struct super_block *sb;__be32 status =0 ;int lkflg;int err;
@@ -6906,7 +6905,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,dprintk ("NFSD: nfsd4_lock: permission denied!\n" );return status; } - sb = cstate->current_fh.fh_dentry->d_sb;if (lock->lk_is_new) {if (nfsd4_has_session (cstate))
@@ -6958,8 +6956,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, fp = lock_stp->st_stid.sc_file;switch (lock->lk_type) {case NFS4_READW_LT : -if (nfsd4_has_session (cstate) && - !(sb->s_export_op->flags &EXPORT_OP_SYNC_LOCKS )) +if (nfsd4_has_session (cstate)) fl_flags |=FL_SLEEP ; fallthrough;case NFS4_READ_LT :
@@ -6971,8 +6968,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, fl_type =F_RDLCK ;break ;case NFS4_WRITEW_LT : -if (nfsd4_has_session (cstate) && - !(sb->s_export_op->flags &EXPORT_OP_SYNC_LOCKS )) +if (nfsd4_has_session (cstate)) fl_flags |=FL_SLEEP ; fallthrough;case NFS4_WRITE_LT :
@@ -6993,6 +6989,16 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; } +/* +* Most filesystems with their own ->lock operations will block +* the nfsd thread waiting to acquire the lock. That leads to +* deadlocks (we don't want every nfsd thread tied up waiting +* for file locks), so don't attempt blocking lock notifications +* on those filesystems: +*/ +if (nf->nf_file->f_op->lock) + fl_flags &= ~FL_SLEEP ; + nbl =find_or_allocate_block (lock_sop, &fp->fi_fhandle, nn);if (!nbl) {dprintk ("NFSD: %s: unable to allocate block!\n" , __func__);
include/linux/exportfs.h +0 -2
@@ -221,8 +221,6 @@ struct export_operations {#define EXPORT_OP_NOATOMIC_ATTR (0x10)/* Filesystem cannot supply atomic attribute updates */ -#define EXPORT_OP_SYNC_LOCKS (0x20)/* Filesystem can't do -asychronous blocking locks */ unsigned long flags; };
include/linux/lockd/lockd.h +7 -2
@@ -303,10 +303,15 @@ void nlmsvc_invalidate_all(void);int nlmsvc_unlock_all_by_sb (struct super_block *sb);int nlmsvc_unlock_all_by_ip (struct sockaddr *server_addr); +static inline struct file *nlmsvc_file_file (struct nlm_file *file) +{ +return file->f_file[O_RDONLY ] ? + file->f_file[O_RDONLY ] : file->f_file[O_WRONLY ]; +} +static inline struct inode *nlmsvc_file_inode (struct nlm_file *file) { -return locks_inode (file->f_file[O_RDONLY ] ? - file->f_file[O_RDONLY ] : file->f_file[O_WRONLY ]); +return locks_inode (nlmsvc_file_file (file)); }static inline int __nlm_privileged_request4 (const struct sockaddr *sap)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 446/770 nfsd4: add refcount for nfsd4_blocked_lock
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasily Averin <[email protected]>
[ Upstream commit 47446d74f1707049067fee038507cdffda805631 ]
nbl allocated in nfsd4_lock can be released by a several ways:
directly in nfsd4_lock(), via nfs4_laundromat(), via another nfs command RELEASE_LOCKOWNER or via nfsd4_callback.
This structure should be refcounted to be used and released correctly in all these cases.
Refcount is initialized to 1 during allocation and is incremented when nbl is added into nbl_list/nbl_lru lists.
Usually nbl is linked into both lists together, so only one refcount is used for both lists.
However nfsd4_lock() should keep in mind that nbl can be present in one of lists only. This can happen if nbl was handled already by nfs4_laundromat/nfsd4_callback/etc.
Refcount is decremented if vfs_lock_file() returns FILE_LOCK_DEFERRED, because nbl can be handled already by nfs4_laundromat/nfsd4_callback/etc.
Refcount is not changed in find_blocked_lock() because of it reuses counter released after removing nbl from lists.
--- fs/nfsd/nfs4state.c | 25 ++++++++++++++++++++++--- fs/nfsd/state.h | 1 + 2 files changed, 23 insertions(+), 3 deletions(-)
fs/nfsd/nfs4state.c +22 -3
@@ -246,6 +246,7 @@ find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh,list_for_each_entry (cur, &lo->lo_blocked, nbl_list) {if (fh_match (fh, &cur->nbl_fh)) {list_del_init (&cur->nbl_list); +WARN_ON (list_empty (&cur->nbl_lru));list_del_init (&cur->nbl_lru); found = cur;break ;
@@ -271,6 +272,7 @@ find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh,INIT_LIST_HEAD (&nbl->nbl_lru);fh_copy_shallow (&nbl->nbl_fh, fh);locks_init_lock (&nbl->nbl_lock); +kref_init (&nbl->nbl_kref);nfsd4_init_cb (&nbl->nbl_cb, lo->lo_owner.so_client, &nfsd4_cb_notify_lock_ops,NFSPROC4_CLNT_CB_NOTIFY_LOCK );
@@ -279,12 +281,21 @@ find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh,return nbl; } +static void +free_nbl (struct kref *kref) +{ +struct nfsd4_blocked_lock *nbl; + + nbl = container_of(kref, struct nfsd4_blocked_lock, nbl_kref); +kfree (nbl); +} +static void free_blocked_lock (struct nfsd4_blocked_lock *nbl) {locks_delete_block (&nbl->nbl_lock);locks_release_private (&nbl->nbl_lock); -kfree (nbl); +kref_put (&nbl->nbl_kref, free_nbl); } static void
@@ -302,6 +313,7 @@ remove_blocked_locks(struct nfs4_lockowner *lo) struct nfsd4_blocked_lock, nbl_list);list_del_init (&nbl->nbl_list); +WARN_ON (list_empty (&nbl->nbl_lru));list_move (&nbl->nbl_lru, &reaplist); }spin_unlock (&nn->blocked_locks_lock);
@@ -7029,6 +7041,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,spin_lock (&nn->blocked_locks_lock);list_add_tail (&nbl->nbl_list, &lock_sop->lo_blocked);list_add_tail (&nbl->nbl_lru, &nn->blocked_locks_lru); +kref_get (&nbl->nbl_kref);spin_unlock (&nn->blocked_locks_lock); }
@@ -7041,6 +7054,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nn->somebody_reclaimed = true;break ;case FILE_LOCK_DEFERRED : +kref_put (&nbl->nbl_kref, free_nbl); nbl =NULL ; fallthrough;case -EAGAIN :/* conflock holds conflicting lock */
@@ -7061,8 +7075,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,/* dequeue it if we queued it before */ if (fl_flags &FL_SLEEP ) {spin_lock (&nn->blocked_locks_lock); -list_del_init (&nbl->nbl_list); -list_del_init (&nbl->nbl_lru); +if (!list_empty (&nbl->nbl_list) && + !list_empty (&nbl->nbl_lru)) { +list_del_init (&nbl->nbl_list); +list_del_init (&nbl->nbl_lru); +kref_put (&nbl->nbl_kref, free_nbl); + } +/* nbl can use one of lists to be linked to reaplist */ spin_unlock (&nn->blocked_locks_lock); }free_blocked_lock (nbl);
fs/nfsd/state.h +1 -0
@@ -633,6 +633,7 @@ struct nfsd4_blocked_lock {struct file_lock nbl_lock;struct knfsd_fh nbl_fh;struct nfsd4_callback nbl_cb; +struct kref nbl_kref; };struct nfsd4_compound_state ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 447/770 NFSD: Fix zero-length NFSv3 WRITEs
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 6a2f774424bfdcc2df3e17de0cefe74a4269cad5 ]
The Linux NFS server currently responds to a zero-length NFSv3 WRITE request with NFS3ERR_IO. It responds to a zero-length NFSv4 WRITE with NFS4_OK and count of zero.
RFC 1813 says of the WRITE procedure's @count argument:
count
The number of bytes of data to be written. If count is 0, the WRITE will succeed and return a count of 0, barring errors due to permissions checking.
RFC 8881 has similar language for NFSv4, though NFSv4 removed the explicit @count argument because that value is already contained in the opaque payload array.
The synthetic client pynfs's WRT4 and WRT15 tests do emit zero- length WRITEs to exercise this spec requirement. Commit fdec6114ee1f ("nfsd4: zero-length WRITE should succeed") addressed the same problem there with the same fix.
But interestingly the Linux NFS client does not appear to emit zero- length WRITEs, instead squelching them. I'm not aware of a test that can generate such WRITEs for NFSv3, so I wrote a naive C program to generate a zero-length WRITE and test this fix.
--- fs/nfsd/nfs3proc.c | 6 +----- fs/nfsd/nfsproc.c | 5 ----- 2 files changed, 1 insertion(+), 10 deletions(-)
fs/nfsd/nfs3proc.c +1 -5
@@ -207,15 +207,11 @@ nfsd3_proc_write(struct svc_rqst *rqstp)fh_copy (&resp->fh, &argp->fh); resp->committed = argp->stable; nvecs =svc_fill_write_vector (rqstp, &argp->payload); -if (!nvecs) { - resp->status = nfserr_io; - goto out; - } + resp->status =nfsd_write (rqstp, &resp->fh, argp->offset, rqstp->rq_vec, nvecs, &cnt, resp->committed, resp->verf); resp->count = cnt; -out:return rpc_success; }
fs/nfsd/nfsproc.c +0 -5
@@ -235,10 +235,6 @@ nfsd_proc_write(struct svc_rqst *rqstp) argp->len, argp->offset); nvecs =svc_fill_write_vector (rqstp, &argp->payload); -if (!nvecs) { - resp->status = nfserr_io; - goto out; - } resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), argp->offset, rqstp->rq_vec, nvecs,
@@ -247,7 +243,6 @@ nfsd_proc_write(struct svc_rqst *rqstp) resp->status =fh_getattr (&resp->fh, &resp->stat); else if (resp->status == nfserr_jukebox) return rpc_drop_reply; -out:return rpc_success; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 448/770 nfsd: map EBADF
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peng Tao <[email protected]>
[ Upstream commit b3d0db706c77d02055910fcfe2f6eb5155ff9d5e ]
Now that we have open file cache, it is possible that another client deletes the file and DP will not know about it. Then IO to MDS would fail with BADSTATEID and knfsd would start state recovery, which should fail as well and then nfs read/write will fail with EBADF. And it triggers a WARN() in nfserrno().
-----------[ cut here ]------------
WARNING: CPU: 0 PID: 13529 at fs/nfsd/nfsproc.c:758 nfserrno+0x58/0x70 [nfsd]() nfsd: non-standard errno: -9 modules linked in: nfsv3 nfs_layout_flexfiles rpcsec_gss_krb5 nfsv4 dns_resolver nfs fscache ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_connt pata_acpi floppy CPU: 0 PID: 13529 Comm: nfsd Tainted: G W 4.1.5-00307-g6e6579b #7 Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 09/30/2014 0000000000000000 00000000464e6c9c ffff88079085fba8 ffffffff81789936 0000000000000000 ffff88079085fc00 ffff88079085fbe8 ffffffff810a08ea ffff88079085fbe8 ffff88080f45c900 ffff88080f627d50 ffff880790c46a48 all Trace: [<ffffffff81789936>] dump_stack+0x45/0x57 [<ffffffff810a08ea>] warn_slowpath_common+0x8a/0xc0 [<ffffffff810a0975>] warn_slowpath_fmt+0x55/0x70 [<ffffffff81252908>] ? splice_direct_to_actor+0x148/0x230 [<ffffffffa02fb8c0>] ? fsid_source+0x60/0x60 [nfsd] [<ffffffffa02f9918>] nfserrno+0x58/0x70 [nfsd] [<ffffffffa02fba57>] nfsd_finish_read+0x97/0xb0 [nfsd] [<ffffffffa02fc7a6>] nfsd_splice_read+0x76/0xa0 [nfsd] [<ffffffffa02fcca1>] nfsd_read+0xc1/0xd0 [nfsd] [<ffffffffa0233af2>] ? svc_tcp_adjust_wspace+0x12/0x30 [sunrpc] [<ffffffffa03073da>] nfsd3_proc_read+0xba/0x150 [nfsd] [<ffffffffa02f7a03>] nfsd_dispatch+0xc3/0x210 [nfsd] [<ffffffffa0233af2>] ? svc_tcp_adjust_wspace+0x12/0x30 [sunrpc] [<ffffffffa0232913>] svc_process_common+0x453/0x6f0 [sunrpc] [<ffffffffa0232cc3>] svc_process+0x113/0x1b0 [sunrpc] [<ffffffffa02f740f>] nfsd+0xff/0x170 [nfsd] [<ffffffffa02f7310>] ? nfsd_destroy+0x80/0x80 [nfsd] [<ffffffff810bf3a8>] kthread+0xd8/0xf0 [<ffffffff810bf2d0>] ? kthread_create_on_node+0x1b0/0x1b0 [<ffffffff817912a2>] ret_from_fork+0x42/0x70 [<ffffffff810bf2d0>] ? kthread_create_on_node+0x1b0/0x1b0
--- fs/nfsd/nfsproc.c | 1 + 1 file changed, 1 insertion(+)
fs/nfsd/nfsproc.c +1 -0
@@ -845,6 +845,7 @@ nfserrno (int errno) { nfserr_io, -EIO }, { nfserr_nxio, -ENXIO }, { nfserr_fbig, -E2BIG }, + { nfserr_stale, -EBADF }, { nfserr_acces, -EACCES }, { nfserr_exist, -EEXIST }, { nfserr_xdev, -EXDEV },
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 449/770 nfsd: Add errno mapping for EREMOTEIO
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <[email protected]>
[ Upstream commit a2694e51f60c5a18c7e43d1a9feaa46d7f153e65 ]
The NFS client can occasionally return EREMOTEIO when signalling issues with the server. ...map to NFSERR_IO.
--- fs/nfsd/nfsproc.c | 1 + 1 file changed, 1 insertion(+)
fs/nfsd/nfsproc.c +1 -0
@@ -874,6 +874,7 @@ nfserrno (int errno) { nfserr_toosmall, -ETOOSMALL }, { nfserr_serverfault, -ESERVERFAULT }, { nfserr_serverfault, -ENFILE }, + { nfserr_io, -EREMOTEIO }, { nfserr_io, -EUCLEAN }, { nfserr_perm, -ENOKEY }, { nfserr_no_grace, -ENOGRACE},
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 450/770 nfsd: Retry once in nfsd_open on an -EOPENSTALE return
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <[email protected]>
[ Upstream commit 12bcbd40fd931472c7fc9cf3bfe66799ece93ed8 ]
If we get back -EOPENSTALE from an NFSv4 open, then we either got some unhandled error or the inode we got back was not the same as the one associated with the dentry.
We really have no recourse in that situation other than to retry the open, and if it fails to just return nfserr_stale back to the client.
--- fs/nfsd/nfsproc.c | 1 + fs/nfsd/vfs.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-)
fs/nfsd/nfsproc.c +1 -0
@@ -875,6 +875,7 @@ nfserrno (int errno) { nfserr_serverfault, -ESERVERFAULT }, { nfserr_serverfault, -ENFILE }, { nfserr_io, -EREMOTEIO }, + { nfserr_stale, -EOPENSTALE }, { nfserr_io, -EUCLEAN }, { nfserr_perm, -ENOKEY }, { nfserr_no_grace, -ENOGRACE},
fs/nfsd/vfs.c +9 -1
@@ -805,6 +805,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int may_flags, struct file **filp) { __be32 err; +bool retried = false;validate_process_creds ();/*
@@ -820,9 +821,16 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,*/ if (type ==S_IFREG ) may_flags |=NFSD_MAY_OWNER_OVERRIDE ; +retry: err =fh_verify (rqstp, fhp, type, may_flags); -if (!err) +if (!err) { err =__nfsd_open (rqstp, fhp, type, may_flags, filp); +if (err == nfserr_stale && !retried) { + retried = true; +fh_put (fhp); + goto retry; + } + }validate_process_creds ();return err; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 451/770 NFSD: Clean up nfsd_vfs_write()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 33388b3aefefd4d83764dab8038cb54068161a44 ]
The RWF_SYNC and !RWF_SYNC arms are now exactly alike except that the RWF_SYNC arm resets the boot verifier twice in a row. Fix that redundancy and de-duplicate the code.
--- fs/nfsd/vfs.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-)
fs/nfsd/vfs.c +5 -16
@@ -1023,22 +1023,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,iov_iter_kvec (&iter,WRITE , vec, vlen, *cnt); since =READ_ONCE (file->f_wb_err); -if (flags &RWF_SYNC ) { -if (verf) -nfsd_copy_boot_verifier (verf, -net_generic (SVC_NET (rqstp), - nfsd_net_id)); - host_err =vfs_iter_write (file, &iter, &pos, flags); -if (host_err <0 ) -nfsd_reset_boot_verifier (net_generic (SVC_NET (rqstp), - nfsd_net_id)); - }else { -if (verf) -nfsd_copy_boot_verifier (verf, -net_generic (SVC_NET (rqstp), - nfsd_net_id)); - host_err =vfs_iter_write (file, &iter, &pos, flags); - } +if (verf) +nfsd_copy_boot_verifier (verf, +net_generic (SVC_NET (rqstp), + nfsd_net_id)); + host_err =vfs_iter_write (file, &iter, &pos, flags);if (host_err <0 ) {nfsd_reset_boot_verifier (net_generic (SVC_NET (rqstp), nfsd_net_id));
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 452/770 NFSD: De-duplicate net_generic(SVC_NET(rqstp), nfsd_net_id)
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit fb7622c2dbd1aa41133a8c73e1137b833c074519 ]
Since this pointer is used repeatedly, move it to a stack variable.
--- fs/nfsd/vfs.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
fs/nfsd/vfs.c +4 -7
@@ -980,6 +980,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, unsigned long *cnt, int stable, __be32 *verf) { + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);struct file *file = nf->nf_file;struct super_block *sb =file_inode (file)->i_sb;struct svc_export *exp;
@@ -1024,13 +1025,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,iov_iter_kvec (&iter,WRITE , vec, vlen, *cnt); since =READ_ONCE (file->f_wb_err);if (verf) -nfsd_copy_boot_verifier (verf, -net_generic (SVC_NET (rqstp), - nfsd_net_id)); +nfsd_copy_boot_verifier (verf, nn); host_err =vfs_iter_write (file, &iter, &pos, flags);if (host_err <0 ) { -nfsd_reset_boot_verifier (net_generic (SVC_NET (rqstp), - nfsd_net_id)); +nfsd_reset_boot_verifier (nn); goto out_nfserr; } *cnt = host_err;
@@ -1043,8 +1041,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,if (stable && use_wgather) { host_err =wait_for_concurrent_writes (file);if (host_err <0 ) -nfsd_reset_boot_verifier (net_generic (SVC_NET (rqstp), - nfsd_net_id)); +nfsd_reset_boot_verifier (nn); } out_nfserr:
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 453/770 NFSD: De-duplicate net_generic(nf->nf_net, nfsd_net_id)
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 2c445a0e72cb1fbfbdb7f9473c53556ee27c1d90 ]
Since this pointer is used repeatedly, move it to a stack variable.
--- fs/nfsd/vfs.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
fs/nfsd/vfs.c +5 -6
@@ -1129,6 +1129,7 @@ __be32 nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, unsigned long count, __be32 *verf) { + struct nfsd_net *nn;struct nfsd_file *nf;loff_t end =LLONG_MAX ;__be32 err = nfserr_inval;
@@ -1145,6 +1146,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf);if (err) goto out; + nn =net_generic (nf->nf_net, nfsd_net_id);if (EX_ISSYNC (fhp->fh_export)) {errseq_t since =READ_ONCE (nf->nf_file->f_wb_err);int err2;
@@ -1152,8 +1154,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, err2 =vfs_fsync_range (nf->nf_file, offset, end,0 );switch (err2) {case 0 : -nfsd_copy_boot_verifier (verf,net_generic (nf->nf_net, - nfsd_net_id)); +nfsd_copy_boot_verifier (verf, nn); err2 =filemap_check_wb_err (nf->nf_file->f_mapping, since); err =nfserrno (err2);
@@ -1162,13 +1163,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_notsupp;break ;default : -nfsd_reset_boot_verifier (net_generic (nf->nf_net, - nfsd_net_id)); +nfsd_reset_boot_verifier (nn); err =nfserrno (err2); } }else -nfsd_copy_boot_verifier (verf,net_generic (nf->nf_net, - nfsd_net_id)); +nfsd_copy_boot_verifier (verf, nn);nfsd_file_put (nf); out:
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 454/770 nfsd: Add a tracepoint for errors in nfsd4_clone_file_range()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Trond Myklebust <[email protected]>
[ Upstream commit a2f4c3fa4db94ba44d32a72201927cfd132a8e82 ]
Since a clone error commit can cause the boot verifier to change, we should trace those errors.
--- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/trace.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++ fs/nfsd/vfs.c | 18 +++++++++++++++-- fs/nfsd/vfs.h | 3 ++- 4 files changed, 69 insertions(+), 4 deletions(-)
fs/nfsd/nfs4proc.c +1 -1
@@ -1104,7 +1104,7 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,if (status) goto out; - status =nfsd4_clone_file_range (src, clone->cl_src_pos, + status =nfsd4_clone_file_range (rqstp, src, clone->cl_src_pos, dst, clone->cl_dst_pos, clone->cl_count,EX_ISSYNC (cstate->current_fh.fh_export));
fs/nfsd/trace.h +50 -0
56 lines not on this page · raw message
fs/nfsd/vfs.c +16 -2
@@ -40,6 +40,7 @@#include "../internal.h" #include "acl.h" #include "idmap.h" +#include "xdr4.h" #endif /* CONFIG_NFSD_V4 */ #include "nfsd.h"
@@ -530,8 +531,15 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, }#endif -__be32 nfsd4_clone_file_range (struct nfsd_file *nf_src,u64 src_pos, -struct nfsd_file *nf_dst,u64 dst_pos,u64 count,bool sync) +static struct nfsd4_compound_state *nfsd4_get_cstate (struct svc_rqst *rqstp) +{ +return &((struct nfsd4_compoundres *)rqstp->rq_resp)->cstate; +} + +__be32 nfsd4_clone_file_range (struct svc_rqst *rqstp, +struct nfsd_file *nf_src,u64 src_pos, +struct nfsd_file *nf_dst,u64 dst_pos, +u64 count,bool sync) {struct file *src = nf_src->nf_file;struct file *dst = nf_dst->nf_file;
@@ -558,6 +566,12 @@ __be32 nfsd4_clone_file_range(struct nfsd_file *nf_src, u64 src_pos,if (!status) status =commit_inode_metadata (file_inode (src));if (status <0 ) { +trace_nfsd_clone_file_range_err (rqstp, + &nfsd4_get_cstate (rqstp)->save_fh, + src_pos, + &nfsd4_get_cstate (rqstp)->current_fh, + dst_pos, + count, status);nfsd_reset_boot_verifier (net_generic (nf_dst->nf_net, nfsd_net_id)); ret =nfserrno (status);
fs/nfsd/vfs.h +2 -1
@@ -57,7 +57,8 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, struct xdr_netobj *);__be32 nfsd4_vfs_fallocate (struct svc_rqst *,struct svc_fh *,struct file *,loff_t ,loff_t ,int ); -__be32 nfsd4_clone_file_range (struct nfsd_file *nf_src,u64 src_pos, +__be32 nfsd4_clone_file_range (struct svc_rqst *rqstp, +struct nfsd_file *nf_src,u64 src_pos,struct nfsd_file *nf_dst,u64 dst_pos,u64 count,bool sync);#endif /* CONFIG_NFSD_V4 */
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 455/770 NFSD: Write verifier might go backwards
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit cdc556600c0133575487cc69fb3128440b3c3e92 ]
When vfs_iter_write() starts to fail because a file system is full, a bunch of writes can fail at once with ENOSPC. These writes repeatedly invoke nfsd_reset_boot_verifier() in quick succession.
Ensure that the time it grabs doesn't go backwards due to an ntp adjustment going on at the same time.
--- fs/nfsd/nfssvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfssvc.c +1 -1
@@ -363,7 +363,7 @@ void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn)static void nfsd_reset_boot_verifier_locked (struct nfsd_net *nn) { -ktime_get_real_ts64 (&nn->nfssvc_boot); +ktime_get_raw_ts64 (&nn->nfssvc_boot); }void nfsd_reset_boot_verifier (struct nfsd_net *nn)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 456/770 NFSD: Clean up the nfsd_net::nfssvc_boot field
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 91d2e9b56cf5c80f9efc530d494968369a8a0e0d ]
There are two boot-time fields in struct nfsd_net: one called boot_time and one called nfssvc_boot. The latter is used only to form write verifiers, but its documenting comment declares:
/* Time of server startup */
Since commit 27c438f53e79 ("nfsd: Support the server resetting the boot verifier"), this field can be reset at any time; it's no longer tied to server restart. So that comment is stale.
Also, according to pahole, struct timespec64 is 16 bytes long on x86_64. The nfssvc_boot field is used only to form a write verifier, which is 8 bytes long.
Let's clarify this situation by manufacturing an 8-byte verifier in nfs_reset_boot_verifier() and storing only that in struct nfsd_net.
We're grabbing 128 bits of time, so compress all of those into a 64-bit verifier instead of throwing out the high-order bits. In the future, the siphash_key can be re-used for other hashed objects per-nfsd_net.
--- fs/nfsd/netns.h | 8 +++++--- fs/nfsd/nfsctl.c | 3 ++- fs/nfsd/nfssvc.c | 51 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 45 insertions(+), 17 deletions(-)
fs/nfsd/netns.h +5 -3
@@ -11,6 +11,7 @@#include <net/net_namespace.h> #include <net/netns/generic.h> #include <linux/percpu_counter.h> +#include <linux/siphash.h> /* Hash tables for nfs4_clientid state */ #define CLIENT_HASH_BITS 4
@@ -108,9 +109,8 @@ struct nfsd_net {bool nfsd_net_up;bool lockd_up; -/* Time of server startup */ -struct timespec64 nfssvc_boot; -seqlock_t boot_lock; +seqlock_t writeverf_lock; +unsigned char writeverf[8 ];/* * Max number of connections this nfsd container will allow. Defaults
@@ -187,6 +187,8 @@ struct nfsd_net {char nfsd_name[UNX_MAXNODENAME +1 ];struct nfsd_fcache_disposal *fcache_disposal; + +siphash_key_t siphash_key; };/* Simple check to find out if a given net was properly initialized */
fs/nfsd/nfsctl.c +2 -1
@@ -1484,7 +1484,8 @@ static __net_init int nfsd_init_net(struct net *net) nn->clientid_counter = nn->clientid_base +1 ; nn->s2s_cp_cl_id = nn->clientid_counter++; -seqlock_init (&nn->boot_lock); +get_random_bytes (&nn->siphash_key,sizeof (nn->siphash_key)); +seqlock_init (&nn->writeverf_lock);return 0 ;
fs/nfsd/nfssvc.c +38 -13
77 lines not on this page · raw message
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 457/770 NFSD: Rename boot verifier functions
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 3988a57885eeac05ef89f0ab4d7e47b52fbcf630 ]
Clean up: These functions handle what the specs call a write verifier, which in the Linux NFS server implementation is now divorced from the server's boot instance
--- fs/nfsd/filecache.c | 2 +- fs/nfsd/netns.h | 4 ++-- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfssvc.c | 16 ++++++++-------- fs/nfsd/vfs.c | 16 ++++++++-------- 5 files changed, 20 insertions(+), 20 deletions(-)
fs/nfsd/filecache.c +1 -1
@@ -243,7 +243,7 @@ nfsd_file_do_unhash(struct nfsd_file *nf)trace_nfsd_file_unhash (nf);if (nfsd_file_check_write_error (nf)) -nfsd_reset_boot_verifier (net_generic (nf->nf_net, nfsd_net_id)); +nfsd_reset_write_verifier (net_generic (nf->nf_net, nfsd_net_id)); --nfsd_file_hashtbl[nf->nf_hashval].nfb_count;hlist_del_rcu (&nf->nf_node);atomic_long_dec (&nfsd_filecache_count);
fs/nfsd/netns.h +2 -2
@@ -198,6 +198,6 @@ extern void nfsd_netns_free_versions(struct nfsd_net *nn);extern unsigned int nfsd_net_id; -void nfsd_copy_boot_verifier (__be32 verf[2 ],struct nfsd_net *nn); -void nfsd_reset_boot_verifier (struct nfsd_net *nn); +void nfsd_copy_write_verifier (__be32 verf[2 ],struct nfsd_net *nn); +void nfsd_reset_write_verifier (struct nfsd_net *nn);#endif /* __NFSD_NETNS_H__ */
fs/nfsd/nfs4proc.c +1 -1
@@ -598,7 +598,7 @@ static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)BUILD_BUG_ON (2 *sizeof (*verf) !=sizeof (verifier->data)); -nfsd_copy_boot_verifier (verf,net_generic (net, nfsd_net_id)); +nfsd_copy_write_verifier (verf,net_generic (net, nfsd_net_id)); } static __be32
fs/nfsd/nfssvc.c +8 -8
@@ -346,14 +346,14 @@ static bool nfsd_needs_lockd(struct nfsd_net *nn) }/** -* nfsd_copy_boot_verifier - Atomically copy a write verifier +* nfsd_copy_write_verifier - Atomically copy a write verifier * @verf: buffer in which to receive the verifier cookie * @nn: NFS net namespace * * This function provides a wait-free mechanism for copying the -* namespace's boot verifier without tearing it. +* namespace's write verifier without tearing it. */ -void nfsd_copy_boot_verifier (__be32 verf[2 ],struct nfsd_net *nn) +void nfsd_copy_write_verifier (__be32 verf[2 ],struct nfsd_net *nn) {int seq =0 ;
@@ -364,7 +364,7 @@ void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn)done_seqretry (&nn->writeverf_lock, seq); } -static void nfsd_reset_boot_verifier_locked (struct nfsd_net *nn) +static void nfsd_reset_write_verifier_locked (struct nfsd_net *nn) {struct timespec64 now;u64 verf;
@@ -379,7 +379,7 @@ static void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) }/** -* nfsd_reset_boot_verifier - Generate a new boot verifier +* nfsd_reset_write_verifier - Generate a new write verifier * @nn: NFS net namespace * * This function updates the ->writeverf field of @nn. This field
@@ -391,10 +391,10 @@ static void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn)* server and MUST be unique between instances of the NFSv4.1 * server." */ -void nfsd_reset_boot_verifier (struct nfsd_net *nn) +void nfsd_reset_write_verifier (struct nfsd_net *nn) {write_seqlock (&nn->writeverf_lock); -nfsd_reset_boot_verifier_locked (nn); +nfsd_reset_write_verifier_locked (nn);write_sequnlock (&nn->writeverf_lock); }
@@ -683,7 +683,7 @@ int nfsd_create_serv(struct net *net)register_inet6addr_notifier (&nfsd_inet6addr_notifier);#endif } -nfsd_reset_boot_verifier (nn); +nfsd_reset_write_verifier (nn);return 0 ; }
fs/nfsd/vfs.c +8 -8
@@ -572,8 +572,8 @@ __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, &nfsd4_get_cstate (rqstp)->current_fh, dst_pos, count, status); -nfsd_reset_boot_verifier (net_generic (nf_dst->nf_net, - nfsd_net_id)); +nfsd_reset_write_verifier (net_generic (nf_dst->nf_net, + nfsd_net_id)); ret =nfserrno (status); } }
@@ -1039,10 +1039,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,iov_iter_kvec (&iter,WRITE , vec, vlen, *cnt); since =READ_ONCE (file->f_wb_err);if (verf) -nfsd_copy_boot_verifier (verf, nn); +nfsd_copy_write_verifier (verf, nn); host_err =vfs_iter_write (file, &iter, &pos, flags);if (host_err <0 ) { -nfsd_reset_boot_verifier (nn); +nfsd_reset_write_verifier (nn); goto out_nfserr; } *cnt = host_err;
@@ -1055,7 +1055,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,if (stable && use_wgather) { host_err =wait_for_concurrent_writes (file);if (host_err <0 ) -nfsd_reset_boot_verifier (nn); +nfsd_reset_write_verifier (nn); } out_nfserr:
@@ -1168,7 +1168,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, err2 =vfs_fsync_range (nf->nf_file, offset, end,0 );switch (err2) {case 0 : -nfsd_copy_boot_verifier (verf, nn); +nfsd_copy_write_verifier (verf, nn); err2 =filemap_check_wb_err (nf->nf_file->f_mapping, since); err =nfserrno (err2);
@@ -1177,11 +1177,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_notsupp;break ;default : -nfsd_reset_boot_verifier (nn); +nfsd_reset_write_verifier (nn); err =nfserrno (err2); } }else -nfsd_copy_boot_verifier (verf, nn); +nfsd_copy_write_verifier (verf, nn);nfsd_file_put (nf); out:
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 458/770 NFSD: Trace boot verifier resets
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 75acacb6583df0b9328dc701d8eeea05af49b8b5 ]
According to commit bbf2f098838a ("nfsd: Reset the boot verifier on all write I/O errors"), the Linux NFS server forces all clients to resend pending unstable writes if any server-side write or commit operation encounters an error (say, ENOSPC). This is a rare and quite exceptional event that could require administrative recovery action, so it should be made trace-able. Example trace event:
nfsd-938 [002] 7174.945558: nfsd_writeverf_reset: boot_time= 61cc920d xid=0xdcd62036 error=-28 new verifier=0x08aecc6142515904
--- fs/nfsd/trace.h | 28 ++++++++++++++++++++++++++++ fs/nfsd/vfs.c | 13 ++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-)
fs/nfsd/trace.h +28 -0
@@ -575,6 +575,34 @@ DEFINE_EVENT(nfsd_net_class, nfsd_##name, \DEFINE_NET_EVENT (grace_start);DEFINE_NET_EVENT (grace_complete); +TRACE_EVENT (nfsd_writeverf_reset, +TP_PROTO ( + const struct nfsd_net *nn, + const struct svc_rqst *rqstp, + int error + ), +TP_ARGS (nn, rqstp, error), +TP_STRUCT__entry ( + __field(unsigned long long, boot_time) + __field(u32, xid) + __field(int, error) + __array(unsigned char, verifier, NFS4_VERIFIER_SIZE) + ), +TP_fast_assign ( + __entry->boot_time = nn->boot_time; + __entry->xid = be32_to_cpu(rqstp->rq_xid); + __entry->error = error; + +/* avoid seqlock inside TP_fast_assign */ +memcpy (__entry->verifier, nn->writeverf, + NFS4_VERIFIER_SIZE); + ), +TP_printk ("boot_time=%16llx xid=0x%08x error=%d new verifier=0x%s" , + __entry->boot_time, __entry->xid, __entry->error, +__print_hex_str (__entry->verifier,NFS4_VERIFIER_SIZE ) + ) +); + TRACE_EVENT(nfsd_clid_cred_mismatch, TP_PROTO( const struct nfs4_client *clp,
fs/nfsd/vfs.c +10 -3
@@ -566,14 +566,17 @@ __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp,if (!status) status =commit_inode_metadata (file_inode (src));if (status <0 ) { +struct nfsd_net *nn =net_generic (nf_dst->nf_net, + nfsd_net_id); +trace_nfsd_clone_file_range_err (rqstp, &nfsd4_get_cstate (rqstp)->save_fh, src_pos, &nfsd4_get_cstate (rqstp)->current_fh, dst_pos, count, status); -nfsd_reset_write_verifier (net_generic (nf_dst->nf_net, - nfsd_net_id)); +nfsd_reset_write_verifier (nn); +trace_nfsd_writeverf_reset (nn, rqstp, status); ret =nfserrno (status); } }
@@ -1043,6 +1046,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, host_err =vfs_iter_write (file, &iter, &pos, flags);if (host_err <0 ) {nfsd_reset_write_verifier (nn); +trace_nfsd_writeverf_reset (nn, rqstp, host_err); goto out_nfserr; } *cnt = host_err;
@@ -1054,8 +1058,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,if (stable && use_wgather) { host_err =wait_for_concurrent_writes (file); -if (host_err <0 ) +if (host_err <0 ) {nfsd_reset_write_verifier (nn); +trace_nfsd_writeverf_reset (nn, rqstp, host_err); + } } out_nfserr:
@@ -1178,6 +1184,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,break ;default :nfsd_reset_write_verifier (nn); +trace_nfsd_writeverf_reset (nn, rqstp, err2); err =nfserrno (err2); } }else
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 459/770 Revert "nfsd: skip some unnecessary stats in the v4 case"
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 58f258f65267542959487dbe8b5641754411843d ]
On the wire, I observed NFSv4 OPEN(CREATE) operations sometimes returning a reasonable-looking value in the cinfo.before field and zero in the cinfo.after field.
RFC 8881 Section 10.8.1 says:
Quoted 5 lines
When a client is making changes to a given directory, it needs to determine whether there have been changes made to the directory by other clients. It does this by using the change attribute as reported before and after the directory operation in the associated
change_info4value returned for the operation.
and
Quoted 3 lines
... The post-operation change
value needs to be saved as the basis for futurechange_info4comparisons.
A good quality client implementation therefore saves the zero cinfo.after value. During a subsequent OPEN operation, it will receive a different non-zero value in the cinfo.before field for that directory, and it will incorrectly believe the directory has changed, triggering an undesirable directory cache invalidation.
There are filesystem types where fs_supports_change_attribute() returns false, tmpfs being one. On NFSv4 mounts, this means the fh_getattr() call site in fill_pre_wcc() and fill_post_wcc() is never invoked. Subsequently, nfsd4_change_attribute() is invoked with an uninitialized @stat argument.
In fill_pre_wcc(), @stat contains stale stack garbage, which is then placed on the wire. In fill_post_wcc(), ->fh_post_wc is all zeroes, so zero is placed on the wire. Both of these values are meaningless.
This fix can be applied immediately to stable kernels. Once there are more regression tests in this area, this optimization can be attempted again.
--- fs/nfsd/nfs3xdr.c | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-)
fs/nfsd/nfs3xdr.c +17 -27
@@ -487,11 +487,6 @@ svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr,return true; } -static bool fs_supports_change_attribute (struct super_block *sb) -{ -return sb->s_flags &SB_I_VERSION || sb->s_export_op->fetch_iversion; -} -/* * Fill in the pre_op attr for the wcc data */
@@ -500,26 +495,24 @@ void fill_pre_wcc(struct svc_fh *fhp)struct inode *inode;struct kstat stat;bool v4 = (fhp->fh_maxsize ==NFS4_FHSIZE ); +__be32 err;if (fhp->fh_no_wcc || fhp->fh_pre_saved)return ; inode =d_inode (fhp->fh_dentry); -if (fs_supports_change_attribute (inode->i_sb) || !v4) { -__be32 err =fh_getattr (fhp, &stat); - -if (err) { -/* Grab the times from inode anyway */ - stat.mtime = inode->i_mtime; - stat.ctime = inode->i_ctime; - stat.size = inode->i_size; - } - fhp->fh_pre_mtime = stat.mtime; - fhp->fh_pre_ctime = stat.ctime; - fhp->fh_pre_size = stat.size; + err =fh_getattr (fhp, &stat); +if (err) { +/* Grab the times from inode anyway */ + stat.mtime = inode->i_mtime; + stat.ctime = inode->i_ctime; + stat.size = inode->i_size; }if (v4) fhp->fh_pre_change =nfsd4_change_attribute (&stat, inode); + fhp->fh_pre_mtime = stat.mtime; + fhp->fh_pre_ctime = stat.ctime; + fhp->fh_pre_size = stat.size; fhp->fh_pre_saved = true; }
@@ -530,6 +523,7 @@ void fill_post_wcc(struct svc_fh *fhp) {bool v4 = (fhp->fh_maxsize ==NFS4_FHSIZE );struct inode *inode =d_inode (fhp->fh_dentry); +__be32 err;if (fhp->fh_no_wcc)return ;
@@ -537,16 +531,12 @@ void fill_post_wcc(struct svc_fh *fhp)if (fhp->fh_post_saved)printk ("nfsd: inode locked twice during operation.\n" ); - fhp->fh_post_saved = true; - -if (fs_supports_change_attribute (inode->i_sb) || !v4) { -__be32 err =fh_getattr (fhp, &fhp->fh_post_attr); - -if (err) { - fhp->fh_post_saved = false; - fhp->fh_post_attr.ctime = inode->i_ctime; - } - } + err =fh_getattr (fhp, &fhp->fh_post_attr); +if (err) { + fhp->fh_post_saved = false; + fhp->fh_post_attr.ctime = inode->i_ctime; + }else + fhp->fh_post_saved = true;if (v4) fhp->fh_post_change =nfsd4_change_attribute (&fhp->fh_post_attr, inode);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 460/770 NFSD: Move fill_pre_wcc() and fill_post_wcc()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit fcb5e3fa012351f3b96024c07bc44834c2478213 ]
These functions are related to file handle processing and have nothing to do with XDR encoding or decoding. Also they are no longer NFSv3-specific. As a clean-up, move their definitions to a more appropriate location. WCC is also an NFSv3-specific term, so rename them as general-purpose helpers.
--- fs/nfsd/nfs3xdr.c | 55 -------------------------------------- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfsfh.c | 66 +++++++++++++++++++++++++++++++++++++++++++++- fs/nfsd/nfsfh.h | 40 ++++++++++++++++++---------- fs/nfsd/vfs.c | 8 +++--- 5 files changed, 96 insertions(+), 75 deletions(-)
fs/nfsd/nfs3xdr.c +0 -55
@@ -487,61 +487,6 @@ svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr,return true; } -/* -* Fill in the pre_op attr for the wcc data -*/ -void fill_pre_wcc (struct svc_fh *fhp) -{ -struct inode *inode; -struct kstat stat; -bool v4 = (fhp->fh_maxsize ==NFS4_FHSIZE ); -__be32 err; - -if (fhp->fh_no_wcc || fhp->fh_pre_saved) -return ; - inode =d_inode (fhp->fh_dentry); - err =fh_getattr (fhp, &stat); -if (err) { -/* Grab the times from inode anyway */ - stat.mtime = inode->i_mtime; - stat.ctime = inode->i_ctime; - stat.size = inode->i_size; - } -if (v4) - fhp->fh_pre_change =nfsd4_change_attribute (&stat, inode); - - fhp->fh_pre_mtime = stat.mtime; - fhp->fh_pre_ctime = stat.ctime; - fhp->fh_pre_size = stat.size; - fhp->fh_pre_saved = true; -} - -/* -* Fill in the post_op attr for the wcc data -*/ -void fill_post_wcc (struct svc_fh *fhp) -{ -bool v4 = (fhp->fh_maxsize ==NFS4_FHSIZE ); -struct inode *inode =d_inode (fhp->fh_dentry); -__be32 err; - -if (fhp->fh_no_wcc) -return ; - -if (fhp->fh_post_saved) -printk ("nfsd: inode locked twice during operation.\n" ); - - err =fh_getattr (fhp, &fhp->fh_post_attr); -if (err) { - fhp->fh_post_saved = false; - fhp->fh_post_attr.ctime = inode->i_ctime; - }else - fhp->fh_post_saved = true; -if (v4) - fhp->fh_post_change = -nfsd4_change_attribute (&fhp->fh_post_attr, inode); -} -/* * XDR decode functions */
fs/nfsd/nfs4proc.c +1 -1
@@ -2523,7 +2523,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) goto encode_op; } -fh_clear_wcc (current_fh); +fh_clear_pre_post_attrs (current_fh);/* If op is non-idempotent */ if (op->opdesc->op_flags &OP_MODIFIES_SOMETHING ) {
fs/nfsd/nfsfh.c +65 -1
78 lines not on this page · raw message
fs/nfsd/nfsfh.h +26 -14
@@ -284,12 +284,13 @@ static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh)#endif #ifdef CONFIG_NFSD_V3 -/* -* The wcc data stored in current_fh should be cleared -* between compound ops. + +/** +* fh_clear_pre_post_attrs - Reset pre/post attributes +* @fhp: file handle to be updated +* */ -static inline void -fh_clear_wcc (struct svc_fh *fhp) +static inline void fh_clear_pre_post_attrs (struct svc_fh *fhp) { fhp->fh_post_saved = false; fhp->fh_pre_saved = false;
@@ -323,13 +324,24 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat, return time_to_chattr(&stat->ctime); } -extern void fill_pre_wcc (struct svc_fh *fhp); -extern void fill_post_wcc (struct svc_fh *fhp); -#else -#define fh_clear_wcc (ignored) -#define fill_pre_wcc (ignored) -#define fill_post_wcc (notused) -#endif /* CONFIG_NFSD_V3 */ +extern void fh_fill_pre_attrs (struct svc_fh *fhp); +extern void fh_fill_post_attrs (struct svc_fh *fhp); + +#else /* !CONFIG_NFSD_V3 */ + +static inline void fh_clear_pre_post_attrs (struct svc_fh *fhp) +{ +} + +static inline void fh_fill_pre_attrs (struct svc_fh *fhp) +{ +} + +static inline void fh_fill_post_attrs (struct svc_fh *fhp) +{ +} + +#endif /* !CONFIG_NFSD_V3 */ /*
@@ -355,7 +367,7 @@ fh_lock_nested(struct svc_fh *fhp, unsigned int subclass) inode =d_inode (dentry);inode_lock_nested (inode, subclass); -fill_pre_wcc (fhp); +fh_fill_pre_attrs (fhp); fhp->fh_locked = true; }
@@ -372,7 +384,7 @@ static inline void fh_unlock(struct svc_fh *fhp) {if (fhp->fh_locked) { -fill_post_wcc (fhp); +fh_fill_post_attrs (fhp);inode_unlock (d_inode (fhp->fh_dentry)); fhp->fh_locked = false; }
fs/nfsd/vfs.c +4 -4
@@ -1787,8 +1787,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,* so do it by hand */ trap =lock_rename (tdentry, fdentry); ffhp->fh_locked = tfhp->fh_locked = true; -fill_pre_wcc (ffhp); -fill_pre_wcc (tfhp); +fh_fill_pre_attrs (ffhp); +fh_fill_pre_attrs (tfhp); odentry =lookup_one_len (fname, fdentry, flen); host_err =PTR_ERR (odentry);
@@ -1840,8 +1840,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,* were the same, so again we do it by hand. */ if (!close_cached) { -fill_post_wcc (ffhp); -fill_post_wcc (tfhp); +fh_fill_post_attrs (ffhp); +fh_fill_post_attrs (tfhp); }unlock_rename (tdentry, fdentry); ffhp->fh_locked = tfhp->fh_locked = false;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 461/770 nfsd: fix crash on COPY_NOTIFY with special stateid
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: J. Bruce Fields <[email protected]>
[ Upstream commit 074b07d94e0bb6ddce5690a9b7e2373088e8b33a ]
RTM says "If the special ONE stateid is passed to nfs4_preprocess_stateid_op(), it returns status=0 but does not set *cstid. nfsd4_copy_notify() depends on stid being set if status=0, and thus can crash if the client sends the right COPY_NOTIFY RPC."
RFC 7862 says "The cna_src_stateid MUST refer to either open or locking states provided earlier by the server. If it is invalid, then the operation MUST fail."
The RFC doesn't specify an error, and the choice doesn't matter much as this is clearly illegal client behavior, but bad_stateid seems reasonable.
Simplest is just to guarantee that nfs4_preprocess_stateid_op, called with non-NULL cstid, errors out if it can't return a stateid.
--- fs/nfsd/nfs4state.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/nfsd/nfs4state.c +5 -1
@@ -6097,7 +6097,11 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,return nfserr_grace;if (ZERO_STATEID (stateid) ||ONE_STATEID (stateid)) { - status =check_special_stateids (net, fhp, stateid, flags); +if (cstid) + status = nfserr_bad_stateid; +else + status =check_special_stateids (net, fhp, stateid, + flags); goto done; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 462/770 fanotify: remove variable set but not used
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Li <[email protected]>
[ Upstream commit 217663f101a56ef77f82273818253fff082bf503 ]
The code that uses the pointer info has been removed in 7326e382c21e ("fanotify: report old and/or new parent+name in FAN_RENAME event"). and fanotify_event_info() doesn't change 'event', so the declaration and assignment of info can be removed.
Eliminate the following clang warning:fs/notify/fanotify/fanotify_user.c:161:24: warning: variable ‘info’ set but not used
--- fs/notify/fanotify/fanotify_user.c | 3 --- 1 file changed, 3 deletions(-)
fs/notify/fanotify/fanotify_user.c +0 -3
@@ -146,7 +146,6 @@ static size_t fanotify_event_len(unsigned int info_mode, struct fanotify_event *event) {size_t event_len =FAN_EVENT_METADATA_LEN ; -struct fanotify_info *info;int fh_len;int dot_len =0 ;
@@ -156,8 +155,6 @@ static size_t fanotify_event_len(unsigned int info_mode,if (fanotify_is_error_event (event->mask)) event_len +=FANOTIFY_ERROR_INFO_LEN ; - info =fanotify_event_info (event); -if (fanotify_event_has_any_dir_fh (event)) { event_len +=fanotify_dir_name_info_len (event); } else if ((info_mode & FAN_REPORT_NAME) &&
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 463/770 lockd: fix server crash on reboot of client holding lock
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: J. Bruce Fields <[email protected]>
[ Upstream commit 6e7f90d163afa8fc2efd6ae318e7c20156a5621f ]
I thought I was iterating over the array when actually the iteration is over the values contained in the array?
Ugh, keep it simple.
Symptoms were a null deference in vfs_lock_file() when an NFSv3 client that previously held a lock came back up and sent a notify.
--- fs/lockd/svcsubs.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
fs/lockd/svcsubs.c +9 -8
@@ -179,19 +179,20 @@ nlm_delete_file(struct nlm_file *file)static int nlm_unlock_files (struct nlm_file *file) {struct file_lock lock; -struct file *f; lock.fl_type =F_UNLCK ; lock.fl_start =0 ; lock.fl_end =OFFSET_MAX ; -for (f = file->f_file[0 ]; f <= file->f_file[1 ]; f++) { -if (f &&vfs_lock_file (f,F_SETLK , &lock,NULL ) <0 ) { -pr_warn ("lockd: unlock failure in %s:%d\n" , - __FILE__, __LINE__); -return 1 ; - } - } +if (file->f_file[O_RDONLY ] && +vfs_lock_file (file->f_file[O_RDONLY ],F_SETLK , &lock,NULL )) + goto out_err; +if (file->f_file[O_WRONLY ] && +vfs_lock_file (file->f_file[O_WRONLY ],F_SETLK , &lock,NULL )) + goto out_err;return 0 ; +out_err: +pr_warn ("lockd: unlock failure in %s:%d\n" , __FILE__, __LINE__); +return 1 ; }/*
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 464/770 lockd: fix failure to cleanup client locks
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: J. Bruce Fields <[email protected]>
[ Upstream commit d19a7af73b5ecaac8168712d18be72b9db166768 ]
In my testing, we're sometimes hitting the request->fl_flags & FL_EXISTS case in posix_lock_inode, presumably just by random luck since we're not actually initializing fl_flags here.
This probably didn't matter before commit 7f024fcd5c97 ("Keep read and write fds with each nlm_file") since we wouldn't previously unlock unless we knew there were locks.
But now it causes lockd to give up on removing more locks.
We could just initialize fl_flags, but really it seems dubious to be calling vfs_lock_file with random values in some of the fields.
--- fs/lockd/svcsubs.c | 1 + 1 file changed, 1 insertion(+)
fs/lockd/svcsubs.c +1 -0
@@ -180,6 +180,7 @@ static int nlm_unlock_files(struct nlm_file *file) {struct file_lock lock; +locks_init_lock (&lock); lock.fl_type =F_UNLCK ; lock.fl_start =0 ; lock.fl_end =OFFSET_MAX ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 465/770 NFSD: Fix the behavior of READ near OFFSET_MAX
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 0cb4d23ae08c48f6bf3c29a8e5c4a74b8388b960 ]
Dan Aloni reports:
Quoted 9 lines
Due to commit
8cfb9015280d("NFS: Always provide aligned buffers to the RPC read layers") on the client, a read of0xfffis aligned up to server rsize of0x1000.As a result, in a test where the server has a file of size
0x7fffffffffffffff, and the client tries to read from the offset0x7ffffffffffff000, the read causesloff_toverflow in the server and it returns an NFS code of EINVAL to the client. The client as a result indefinitely retries the request.
The Linux NFS client does not handle NFS?ERR_INVAL, even though all NFS specifications permit servers to return that status code for a READ.
Instead of NFS?ERR_INVAL, have out-of-range READ requests succeed and return a short result. Set the EOF flag in the result to prevent the client from retrying the READ request. This behavior appears to be consistent with Solaris NFS servers.
Note that NFSv3 and NFSv4 use u64 offset values on the wire. These must be converted to loff_t internally before use -- an implicit type cast is not adequate for this purpose. Otherwise VFS checks against sb->s_maxbytes do not work properly.
--- fs/nfsd/nfs3proc.c | 8 ++++++-- fs/nfsd/nfs4proc.c | 8 ++++++-- fs/nfsd/nfs4xdr.c | 8 ++------ 3 files changed, 14 insertions(+), 10 deletions(-)
fs/nfsd/nfs3proc.c +6 -2
@@ -150,13 +150,17 @@ nfsd3_proc_read(struct svc_rqst *rqstp)unsigned int len;int v; - argp->count =min_t (u32, argp->count, max_blocksize); -dprintk ("nfsd: READ(3) %s %lu bytes at %Lu\n" ,SVCFH_fmt (&argp->fh), (unsigned long ) argp->count, (unsigned long long ) argp->offset); + argp->count =min_t (u32, argp->count, max_blocksize); +if (argp->offset > (u64 )OFFSET_MAX ) + argp->offset = (u64 )OFFSET_MAX ; +if (argp->offset + argp->count > (u64 )OFFSET_MAX ) + argp->count = (u64 )OFFSET_MAX - argp->offset; + v =0 ; len = argp->count; resp->pages = rqstp->rq_next_page;
fs/nfsd/nfs4proc.c +6 -2
@@ -782,12 +782,16 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,__be32 status; read->rd_nf =NULL ; -if (read->rd_offset >=OFFSET_MAX ) -return nfserr_inval;trace_nfsd_read_start (rqstp, &cstate->current_fh, read->rd_offset, read->rd_length); + read->rd_length =min_t (u32, read->rd_length,svc_max_payload (rqstp)); +if (read->rd_offset > (u64 )OFFSET_MAX ) + read->rd_offset = (u64 )OFFSET_MAX ; +if (read->rd_offset + read->rd_length > (u64 )OFFSET_MAX ) + read->rd_length = (u64 )OFFSET_MAX - read->rd_offset; +/* * If we do a zero copy read, then a client will see read data * that reflects the state of the file *after* performing the
fs/nfsd/nfs4xdr.c +2 -6
@@ -3997,10 +3997,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, }xdr_commit_encode (xdr); - maxcount =svc_max_payload (resp->rqstp); - maxcount = min_t(unsigned long, maxcount, + maxcount = min_t(unsigned long, read->rd_length, (xdr->buf->buflen - xdr->buf->len)); - maxcount = min_t(unsigned long, maxcount, read->rd_length);if (file->f_op->splice_read &&test_bit (RQ_SPLICE_OK , &resp->rqstp->rq_flags))
@@ -4834,10 +4832,8 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,return nfserr_resource;xdr_commit_encode (xdr); - maxcount =svc_max_payload (resp->rqstp); - maxcount = min_t(unsigned long, maxcount, + maxcount = min_t(unsigned long, read->rd_length, (xdr->buf->buflen - xdr->buf->len)); - maxcount = min_t(unsigned long, maxcount, read->rd_length); count = maxcount; eof = read->rd_offset >=i_size_read (file_inode (file));
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 466/770 NFSD: Fix ia_size underflow
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit e6faac3f58c7c4176b66f63def17a34232a17b0e ]
iattr::ia_size is a loff_t, which is a signed 64-bit type. NFSv3 and NFSv4 both define file size as an unsigned 64-bit type. Thus there is a range of valid file size values an NFS client can send that is already larger than Linux can handle.
Currently decode_fattr4() dumps a full u64 value into ia_size. If that value happens to be larger than S64_MAX, then ia_size underflows. I'm about to fix up the NFSv3 behavior as well, so let's catch the underflow in the common code path: nfsd_setattr().
--- fs/nfsd/vfs.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/nfsd/vfs.c +4 -0
@@ -449,6 +449,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, .ia_size = iap->ia_size, }; + host_err = -EFBIG ; +if (iap->ia_size <0 ) + goto out_unlock; + host_err =notify_change (dentry, &size_attr,NULL );if (host_err) goto out_unlock;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 467/770 NFSD: Fix NFSv3 SETATTR/CREATEs handling of large file sizes
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit a648fdeb7c0e17177a2280344d015dba3fbe3314 ]
iattr::ia_size is a loff_t, so these NFSv3 procedures must be careful to deal with incoming client size values that are larger than s64_max without corrupting the value.
Silently capping the value results in storing a different value than the client passed in which is unexpected behavior, so remove the min_t() check in decode_sattr3().
Note that RFC 1813 permits only the WRITE procedure to return NFS3ERR_FBIG. We believe that NFSv3 reference implementations also return NFS3ERR_FBIG when ia_size is too large.
--- fs/nfsd/nfs3xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfs3xdr.c +1 -1
@@ -254,7 +254,7 @@ svcxdr_decode_sattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,if (xdr_stream_decode_u64 (xdr, &newsize) <0 )return false; iap->ia_valid |=ATTR_SIZE ; - iap->ia_size =min_t (u64, newsize,NFS_OFFSET_MAX ); + iap->ia_size = newsize; }if (xdr_stream_decode_u32 (xdr, &set_it) <0 )return false;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 468/770 NFSD: COMMIT operations must not return NFS?ERR_INVAL
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 3f965021c8bc38965ecb1924f570c4842b33d408 ]
Since, well, forever, the Linux NFS server's nfsd_commit() function has returned nfserr_inval when the passed-in byte range arguments were non-sensical.
However, according to RFC 1813 section 3.3.21, NFSv3 COMMIT requests are permitted to return only the following non-zero status codes:
NFS3ERR_IO
NFS3ERR_STALE
NFS3ERR_BADHANDLE
NFS3ERR_SERVERFAULT
NFS3ERR_INVAL is not included in that list. Likewise, NFS4ERR_INVAL is not listed in the COMMIT row of Table 6 in RFC 8881.
RFC 7530 does permit COMMIT to return NFS4ERR_INVAL, but does not specify when it can or should be used.
Instead of dropping or failing a COMMIT request in a byte range that is not supported, turn it into a valid request by treating one or both arguments as zero. Offset zero means start-of-file, count zero means until-end-of-file, so we only ever extend the commit range. NFS servers are always allowed to commit more and sooner than requested.
The range check is no longer bounded by NFS_OFFSET_MAX, but rather by the value that is returned in the maxfilesize field of the NFSv3 FSINFO procedure or the NFSv4 maxfilesize file attribute.
Note that this change results in a new pynfs failure:
CMT4 st_commit.testCommitOverflow : RUNNING CMT4 st_commit.testCommitOverflow : FAILURE
COMMIT with offset + count overflow should return NFS4ERR_INVAL, instead got NFS4_OK
IMO the test is not correct as written: RFC 8881 does not allow the COMMIT operation to return NFS4ERR_INVAL.
--- fs/nfsd/nfs3proc.c | 6 ------ fs/nfsd/vfs.c | 53 +++++++++++++++++++++++++++++++--------------- fs/nfsd/vfs.h | 4 ++-- 3 files changed, 38 insertions(+), 25 deletions(-)
fs/nfsd/nfs3proc.c +0 -6
@@ -660,15 +660,9 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) argp->count, (unsigned long long) argp->offset); -if (argp->offset >NFS_OFFSET_MAX ) { - resp->status = nfserr_inval; - goto out; - } -fh_copy (&resp->fh, &argp->fh); resp->status =nfsd_commit (rqstp, &resp->fh, argp->offset, argp->count, resp->verf); -out:return rpc_success; }
fs/nfsd/vfs.c +36 -17
78 lines not on this page · raw message
fs/nfsd/vfs.h +2 -2
@@ -74,8 +74,8 @@ __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, struct svc_fh *res, int createmode, u32 *verifier, bool *truncp, bool *created); -__be32 nfsd_commit (struct svc_rqst *,struct svc_fh *, -loff_t ,unsigned long ,__be32 *verf); +__be32 nfsd_commit (struct svc_rqst *rqst,struct svc_fh *fhp, +u64 offset,u32 count,__be32 *verf);#endif /* CONFIG_NFSD_V3 */ #ifdef CONFIG_NFSD_V4 __be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 469/770 NFSD: Deprecate NFS_OFFSET_MAX
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit c306d737691ef84305d4ed0d302c63db2932f0bb ]
NFS_OFFSET_MAX was introduced way back in Linux v2.3.y before there was a kernel-wide OFFSET_MAX value. As a clean up, replace the last few uses of it with its generic equivalent, and get rid of it.
--- fs/nfsd/nfs3xdr.c | 2 +- fs/nfsd/nfs4xdr.c | 2 +- include/linux/nfs.h | 8 -------- 3 files changed, 2 insertions(+), 10 deletions(-)
fs/nfsd/nfs3xdr.c +1 -1
@@ -1060,7 +1060,7 @@ svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name,return false;/* cookie */ resp->cookie_offset = dirlist->len; -if (xdr_stream_encode_u64 (xdr,NFS_OFFSET_MAX ) <0 ) +if (xdr_stream_encode_u64 (xdr,OFFSET_MAX ) <0 )return false;return true;
fs/nfsd/nfs4xdr.c +1 -1
@@ -3495,7 +3495,7 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, p =xdr_reserve_space (xdr,3 *4 + namlen);if (!p) goto fail; - p =xdr_encode_hyper (p,NFS_OFFSET_MAX );/* offset of next entry */ + p =xdr_encode_hyper (p,OFFSET_MAX );/* offset of next entry */ p =xdr_encode_array (p, name, namlen);/* name length & name */ nfserr =nfsd4_encode_dirent_fattr (xdr, cd, name, namlen);
include/linux/nfs.h +0 -8
@@ -36,14 +36,6 @@ static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *sourcmemcpy (target->data, source->data, source->size); } - -/* -* This is really a general kernel constant, but since nothing like -* this is defined in the kernel headers, I have to do it here. -*/ -#define NFS_OFFSET_MAX ((__s64)((~(__u64)0) >> 1)) - -enum nfs3_stable_how {NFS_UNSTABLE =0 ,NFS_DATA_SYNC =1 ,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 470/770 nfsd: Add support for the birth time attribute
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ondrej Valousek <[email protected]>
[ Upstream commit e377a3e698fb56cb63f6bddbebe7da76dc37e316 ]
For filesystems that supports "btime" timestamp (i.e. most modern filesystems do) we share it via kernel nfsd. Btime support for NFS client has already been added by Trond recently.
--- fs/nfsd/nfs4xdr.c | 10 ++++++++++ fs/nfsd/nfsd.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-)
fs/nfsd/nfs4xdr.c +10 -0
@@ -2854,6 +2854,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, err =vfs_getattr (&path, &stat,STATX_BASIC_STATS ,AT_STATX_SYNC_AS_STAT );if (err) goto out_nfserr; +if (!(stat.result_mask &STATX_BTIME )) +/* underlying FS does not offer btime so we can't share it */ + bmval1 &= ~FATTR4_WORD1_TIME_CREATE ; if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) || (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
@@ -3254,6 +3257,13 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p =xdr_encode_hyper (p, (s64 )stat.mtime.tv_sec); *p++ =cpu_to_be32 (stat.mtime.tv_nsec); } +if (bmval1 &FATTR4_WORD1_TIME_CREATE ) { + p =xdr_reserve_space (xdr,12 ); +if (!p) + goto out_resource; + p =xdr_encode_hyper (p, (s64 )stat.btime.tv_sec); + *p++ =cpu_to_be32 (stat.btime.tv_nsec); + }if (bmval1 &FATTR4_WORD1_MOUNTED_ON_FILEID ) {struct kstat parent_stat;u64 ino = stat.ino;
fs/nfsd/nfsd.h +1 -1
@@ -364,7 +364,7 @@ void nfsd_lockd_shutdown(void); | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \ | FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \ | FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \ - | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ + | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_CREATE \ | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)#define NFSD4_SUPPORTED_ATTRS_WORD2 0
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 471/770 NFSD: De-duplicate hash bucket indexing
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 378a6109dd142a678f629b740f558365150f60f9 ]
Clean up: The details of finding the right hash bucket are exactly the same in both nfsd_cache_lookup() and nfsd_cache_update().
--- fs/nfsd/nfscache.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-)
fs/nfsd/nfscache.c +10 -12
@@ -84,12 +84,6 @@ nfsd_hashsize(unsigned int limit)return roundup_pow_of_two (limit /TARGET_BUCKET_SIZE ); } -static u32 -nfsd_cache_hash (__be32 xid,struct nfsd_net *nn) -{ -return hash_32 ((__force u32 )xid, nn->maskbits); -} -static struct svc_cacherep *nfsd_reply_cache_alloc (struct svc_rqst *rqstp,__wsum csum,struct nfsd_net *nn)
@@ -241,6 +235,14 @@ lru_put_end(struct nfsd_drc_bucket *b, struct svc_cacherep *rp)list_move_tail (&rp->c_lru, &b->lru_head); } +static noinline struct nfsd_drc_bucket * +nfsd_cache_bucket_find (__be32 xid,struct nfsd_net *nn) +{ +unsigned int hash =hash_32 ((__force u32 )xid, nn->maskbits); + +return &nn->drc_hashtbl[hash]; +} +static long prune_bucket (struct nfsd_drc_bucket *b,struct nfsd_net *nn,unsigned int max) {
@@ -421,10 +423,8 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) {struct nfsd_net *nn =net_generic (SVC_NET (rqstp), nfsd_net_id);struct svc_cacherep *rp, *found; -__be32 xid = rqstp->rq_xid;__wsum csum; -u32 hash =nfsd_cache_hash (xid, nn); -struct nfsd_drc_bucket *b = &nn->drc_hashtbl[hash]; +struct nfsd_drc_bucket *b =nfsd_cache_bucket_find (rqstp->rq_xid, nn);int type = rqstp->rq_cachetype;int rtn =RC_DOIT ;
@@ -528,7 +528,6 @@ void nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)struct nfsd_net *nn =net_generic (SVC_NET (rqstp), nfsd_net_id);struct svc_cacherep *rp = rqstp->rq_cacherep;struct kvec *resv = &rqstp->rq_res.head[0 ], *cachv; -u32 hash;struct nfsd_drc_bucket *b;int len;size_t bufsize =0 ;
@@ -536,8 +535,7 @@ void nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)if (!rp)return ; - hash =nfsd_cache_hash (rp->c_key.k_xid, nn); - b = &nn->drc_hashtbl[hash]; + b =nfsd_cache_bucket_find (rp->c_key.k_xid, nn); len = resv->iov_len - ((char *)statp - (char *)resv->iov_base); len >>=2 ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 472/770 NFSD: Skip extra computation for RC_NOCACHE case
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 0f29ce32fbc56cfdb304eec8a4deb920ccfd89c3 ]
Force the compiler to skip unneeded initialization for cases that don't need those values. For example, NFSv4 COMPOUND operations are RC_NOCACHE.
--- fs/nfsd/nfscache.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/nfsd/nfscache.c +4 -2
@@ -421,10 +421,10 @@ nfsd_cache_insert(struct nfsd_drc_bucket *b, struct svc_cacherep *key,*/ int nfsd_cache_lookup (struct svc_rqst *rqstp) { -struct nfsd_net *nn =net_generic (SVC_NET (rqstp), nfsd_net_id); +struct nfsd_net *nn;struct svc_cacherep *rp, *found;__wsum csum; -struct nfsd_drc_bucket *b =nfsd_cache_bucket_find (rqstp->rq_xid, nn); +struct nfsd_drc_bucket *b;int type = rqstp->rq_cachetype;int rtn =RC_DOIT ;
@@ -440,10 +440,12 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp)* Since the common case is a cache miss followed by an insert, * preallocate an entry. */ + nn =net_generic (SVC_NET (rqstp), nfsd_net_id); rp =nfsd_reply_cache_alloc (rqstp, csum, nn);if (!rp) goto out; + b =nfsd_cache_bucket_find (rqstp->rq_xid, nn);spin_lock (&b->cache_lock); found =nfsd_cache_insert (b, rp, nn);if (found != rp) {
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 473/770 NFSD: Streamline the rare "found" case
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit add1511c38166cf1036765f8c4aa939f0275a799 ]
Move a rarely called function call site out of the hot path.
This is an exceptionally small improvement because the compiler inlines most of the functions that nfsd_cache_lookup() calls.
--- fs/nfsd/nfscache.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
fs/nfsd/nfscache.c +3 -4
@@ -448,11 +448,8 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) b =nfsd_cache_bucket_find (rqstp->rq_xid, nn);spin_lock (&b->cache_lock); found =nfsd_cache_insert (b, rp, nn); -if (found != rp) { -nfsd_reply_cache_free_locked (NULL , rp, nn); - rp = found; +if (found != rp) goto found_entry; - }nfsd_stats_rc_misses_inc (); rqstp->rq_cacherep = rp;
@@ -470,8 +467,10 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) found_entry:/* We found a matching entry which is either in progress or done. */ +nfsd_reply_cache_free_locked (NULL , rp, nn);nfsd_stats_rc_hits_inc (); rtn =RC_DROPIT ; + rp = found;/* Request being processed */ if (rp->c_state ==RC_INPROG )
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 474/770 SUNRPC: Remove the .svo_enqueue_xprt method
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit a9ff2e99e9fa501ec965da03c18a5422b37a2f44 ]
We have never been able to track down and address the underlying cause of the performance issues with workqueue-based service support. svo_enqueue_xprt is called multiple times per RPC, so it adds instruction path length, but always ends up at the same
function: svc_xprt_do_enqueue(). We do not anticipate needing this flexibility for dynamic nfsd thread management support.
As a micro-optimization, remove .svo_enqueue_xprt because Spectre/Meltdown makes virtual function calls more costly.
This change essentially reverts commit b9e13cdfac70 ("nfsd/sunrpc:
turn enqueueing a svc_xprt into a svc_serv operation").
--- fs/lockd/svc.c | 1 - fs/nfs/callback.c | 2 -- fs/nfsd/nfssvc.c | 1 - include/linux/sunrpc/svc.h | 3 --- include/linux/sunrpc/svc_xprt.h | 1 - net/sunrpc/svc_xprt.c | 10 +++++----- 6 files changed, 5 insertions(+), 13 deletions(-)
fs/lockd/svc.c +0 -1
@@ -353,7 +353,6 @@ static struct notifier_block lockd_inet6addr_notifier = {static const struct svc_serv_ops lockd_sv_ops = { .svo_shutdown = svc_rpcb_cleanup, .svo_function = lockd, - .svo_enqueue_xprt = svc_xprt_do_enqueue, .svo_module =THIS_MODULE , };
fs/nfs/callback.c +0 -2
@@ -234,13 +234,11 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,static const struct svc_serv_ops nfs40_cb_sv_ops = { .svo_function = nfs4_callback_svc, - .svo_enqueue_xprt = svc_xprt_do_enqueue, .svo_module =THIS_MODULE , };#if defined(CONFIG_NFS_V4_1 )static const struct svc_serv_ops nfs41_cb_sv_ops = { .svo_function = nfs41_callback_svc, - .svo_enqueue_xprt = svc_xprt_do_enqueue, .svo_module =THIS_MODULE , };
fs/nfsd/nfssvc.c +0 -1
@@ -615,7 +615,6 @@ static int nfsd_get_default_max_blksize(void)static const struct svc_serv_ops nfsd_thread_sv_ops = { .svo_shutdown = nfsd_last_thread, .svo_function = nfsd, - .svo_enqueue_xprt = svc_xprt_do_enqueue, .svo_module =THIS_MODULE , };
include/linux/sunrpc/svc.h +0 -3
@@ -61,9 +61,6 @@ struct svc_serv_ops {/* function for service threads to run */ int (*svo_function)(void *); -/* queue up a transport for servicing */ -void (*svo_enqueue_xprt)(struct svc_xprt *); -/* optional module to count when adding threads. * Thread function must call module_put_and_kthread_exit() to exit. */
include/linux/sunrpc/svc_xprt.h +0 -1
@@ -131,7 +131,6 @@ int svc_create_xprt(struct svc_serv *, const char *, struct net *, const int, const unsigned short, int, const struct cred *);void svc_xprt_received (struct svc_xprt *xprt); -void svc_xprt_do_enqueue (struct svc_xprt *xprt);void svc_xprt_enqueue (struct svc_xprt *xprt);void svc_xprt_put (struct svc_xprt *xprt);void svc_xprt_copy_addrs (struct svc_rqst *rqstp,struct svc_xprt *xprt);
net/sunrpc/svc_xprt.c +5 -5
@@ -31,6 +31,7 @@ static int svc_deferred_recv(struct svc_rqst *rqstp);static struct cache_deferred_req *svc_defer (struct cache_req *req);static void svc_age_temp_xprts (struct timer_list *t);static void svc_delete_xprt (struct svc_xprt *xprt); +static void svc_xprt_do_enqueue (struct svc_xprt *xprt);/* apparently the "standard" is that clients close * idle connections after 5 minutes, servers after
@@ -253,12 +254,12 @@ void svc_xprt_received(struct svc_xprt *xprt)trace_svc_xprt_received (xprt);/* As soon as we clear busy, the xprt could be closed and -* 'put', so we need a reference to call svc_enqueue_xprt with: +* 'put', so we need a reference to call svc_xprt_do_enqueue with: */ svc_xprt_get (xprt);smp_mb__before_atomic ();clear_bit (XPT_BUSY , &xprt->xpt_flags); - xprt->xpt_server->sv_ops->svo_enqueue_xprt (xprt); +svc_xprt_do_enqueue (xprt);svc_xprt_put (xprt); }EXPORT_SYMBOL_GPL (svc_xprt_received);
@@ -410,7 +411,7 @@ static bool svc_xprt_ready(struct svc_xprt *xprt)return false; } -void svc_xprt_do_enqueue (struct svc_xprt *xprt) +static void svc_xprt_do_enqueue (struct svc_xprt *xprt) {struct svc_pool *pool;struct svc_rqst *rqstp =NULL ;
@@ -454,7 +455,6 @@ void svc_xprt_do_enqueue(struct svc_xprt *xprt)put_cpu ();trace_svc_xprt_do_enqueue (xprt, rqstp); } -EXPORT_SYMBOL_GPL (svc_xprt_do_enqueue);/* * Queue up a transport with data pending. If there are idle nfsd
@@ -465,7 +465,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) {if (test_bit (XPT_BUSY , &xprt->xpt_flags))return ; - xprt->xpt_server->sv_ops->svo_enqueue_xprt (xprt); +svc_xprt_do_enqueue (xprt); }EXPORT_SYMBOL_GPL (svc_xprt_enqueue);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 475/770 SUNRPC: Merge svc_do_enqueue_xprt() into svc_enqueue_xprt()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit c0219c499799c1e92bd570c15a47e6257a27bb15 ]
Neil says:
"These functions were separated in commit 0971374e2818 ("SUNRPC:
Reduce contention in svc_xprt_enqueue()") so that the XPT_BUSY check happened before taking any spinlocks.
We have since moved or removed the spinlocks so the extra test is fairly pointless."
I've made this a separate patch in case the XPT_BUSY change has unexpected consequences and needs to be reverted.
--- net/sunrpc/svc_xprt.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-)
net/sunrpc/svc_xprt.c +10 -16
@@ -31,7 +31,6 @@ static int svc_deferred_recv(struct svc_rqst *rqstp);static struct cache_deferred_req *svc_defer (struct cache_req *req);static void svc_age_temp_xprts (struct timer_list *t);static void svc_delete_xprt (struct svc_xprt *xprt); -static void svc_xprt_do_enqueue (struct svc_xprt *xprt);/* apparently the "standard" is that clients close * idle connections after 5 minutes, servers after
@@ -254,12 +253,12 @@ void svc_xprt_received(struct svc_xprt *xprt)trace_svc_xprt_received (xprt);/* As soon as we clear busy, the xprt could be closed and -* 'put', so we need a reference to call svc_xprt_do_enqueue with: +* 'put', so we need a reference to call svc_xprt_enqueue with: */ svc_xprt_get (xprt);smp_mb__before_atomic ();clear_bit (XPT_BUSY , &xprt->xpt_flags); -svc_xprt_do_enqueue (xprt); +svc_xprt_enqueue (xprt);svc_xprt_put (xprt); }EXPORT_SYMBOL_GPL (svc_xprt_received);
@@ -399,6 +398,8 @@ static bool svc_xprt_ready(struct svc_xprt *xprt)smp_rmb (); xpt_flags =READ_ONCE (xprt->xpt_flags); +if (xpt_flags &BIT (XPT_BUSY )) +return false;if (xpt_flags & (BIT (XPT_CONN ) |BIT (XPT_CLOSE )))return true;if (xpt_flags & (BIT (XPT_DATA ) |BIT (XPT_DEFERRED ))) {
@@ -411,7 +412,12 @@ static bool svc_xprt_ready(struct svc_xprt *xprt)return false; } -static void svc_xprt_do_enqueue (struct svc_xprt *xprt) +/** +* svc_xprt_enqueue - Queue a transport on an idle nfsd thread +* @xprt: transport with data pending +* +*/ +void svc_xprt_enqueue (struct svc_xprt *xprt) {struct svc_pool *pool;struct svc_rqst *rqstp =NULL ;
@@ -455,18 +461,6 @@ static void svc_xprt_do_enqueue(struct svc_xprt *xprt)put_cpu ();trace_svc_xprt_do_enqueue (xprt, rqstp); } - -/* -* Queue up a transport with data pending. If there are idle nfsd -* processes, wake 'em up. -* -*/ -void svc_xprt_enqueue (struct svc_xprt *xprt) -{ -if (test_bit (XPT_BUSY , &xprt->xpt_flags)) -return ; -svc_xprt_do_enqueue (xprt); -}EXPORT_SYMBOL_GPL (svc_xprt_enqueue);/*
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 476/770 SUNRPC: Remove svo_shutdown method
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 87cdd8641c8a1ec6afd2468265e20840a57fd888 ]
Clean up. Neil observed that "any code that calls svc_shutdown_net() knows what the shutdown function should be, and so can call it directly."
--- fs/lockd/svc.c | 5 ++--- fs/nfsd/nfssvc.c | 2 +- include/linux/sunrpc/svc.h | 3 --- net/sunrpc/svc.c | 3 --- 4 files changed, 3 insertions(+), 10 deletions(-)
fs/lockd/svc.c +2 -3
@@ -249,6 +249,7 @@ static int make_socks(struct svc_serv *serv, struct net *net,printk (KERN_WARNING "lockd_up: makesock failed, error=%d\n" , err);svc_shutdown_net (serv, net); +svc_rpcb_cleanup (serv, net);return err; }
@@ -287,8 +288,7 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net)cancel_delayed_work_sync (&ln->grace_period_end);locks_end_grace (&ln->lockd_manager);svc_shutdown_net (serv, net); -dprintk ("%s: per-net data destroyed; net=%x\n" , - __func__, net->ns.inum); +svc_rpcb_cleanup (serv, net); } }else { pr_err("%s: no users! net=%x\n",
@@ -351,7 +351,6 @@ static struct notifier_block lockd_inet6addr_notifier = {#endif static const struct svc_serv_ops lockd_sv_ops = { - .svo_shutdown = svc_rpcb_cleanup, .svo_function = lockd, .svo_module =THIS_MODULE , };
fs/nfsd/nfssvc.c +1 -1
@@ -613,7 +613,6 @@ static int nfsd_get_default_max_blksize(void) }static const struct svc_serv_ops nfsd_thread_sv_ops = { - .svo_shutdown = nfsd_last_thread, .svo_function = nfsd, .svo_module =THIS_MODULE , };
@@ -724,6 +723,7 @@ void nfsd_put(struct net *net)if (kref_put (&nn->nfsd_serv->sv_refcnt, nfsd_noop)) {svc_shutdown_net (nn->nfsd_serv, net); +nfsd_last_thread (nn->nfsd_serv, net);svc_destroy (&nn->nfsd_serv->sv_refcnt);spin_lock (&nfsd_notifier_lock); nn->nfsd_serv =NULL ;
include/linux/sunrpc/svc.h +0 -3
@@ -55,9 +55,6 @@ struct svc_pool {struct svc_serv ;struct svc_serv_ops { -/* Callback to use when last thread exits. */ -void (*svo_shutdown)(struct svc_serv *,struct net *); -/* function for service threads to run */ int (*svo_function)(void *);
net/sunrpc/svc.c +0 -3
@@ -537,9 +537,6 @@ EXPORT_SYMBOL_GPL(svc_create_pooled);void svc_shutdown_net (struct svc_serv *serv,struct net *net) {svc_close_net (serv, net); - -if (serv->sv_ops->svo_shutdown) - serv->sv_ops->svo_shutdown (serv, net); }EXPORT_SYMBOL_GPL (svc_shutdown_net);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 477/770 SUNRPC: Rename svc_create_xprt()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 352ad31448fecc78a2e9b78da64eea5d63b8d0ce ]
Clean up: Use the "svc_xprt_<task>" function naming convention as is used for other external APIs.
--- fs/lockd/svc.c | 4 ++-- fs/nfs/callback.c | 12 ++++++------ fs/nfsd/nfsctl.c | 8 ++++---- fs/nfsd/nfssvc.c | 8 ++++---- include/linux/sunrpc/svc_xprt.h | 7 ++++--- net/sunrpc/svc_xprt.c | 24 +++++++++++++++++++----- 6 files changed, 39 insertions(+), 24 deletions(-)
fs/lockd/svc.c +2 -2
@@ -197,8 +197,8 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name, xprt =svc_find_xprt (serv, name, net, family,0 );if (xprt ==NULL ) -return svc_create_xprt (serv, name, net, family, port, -SVC_SOCK_DEFAULTS , cred); +return svc_xprt_create (serv, name, net, family, port, +SVC_SOCK_DEFAULTS , cred);svc_xprt_put (xprt);return 0 ; }
fs/nfs/callback.c +6 -6
@@ -45,18 +45,18 @@ static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)int ret;struct nfs_net *nn =net_generic (net, nfs_net_id); - ret =svc_create_xprt (serv,"tcp" , net,PF_INET , - nfs_callback_set_tcpport,SVC_SOCK_ANONYMOUS , - cred); + ret =svc_xprt_create (serv,"tcp" , net,PF_INET , + nfs_callback_set_tcpport,SVC_SOCK_ANONYMOUS , + cred);if (ret <=0 ) goto out_err; nn->nfs_callback_tcpport = ret;dprintk ("NFS: Callback listener port = %u (af %u, net %x)\n" , nn->nfs_callback_tcpport,PF_INET , net->ns.inum); - ret =svc_create_xprt (serv,"tcp" , net,PF_INET6 , - nfs_callback_set_tcpport,SVC_SOCK_ANONYMOUS , - cred); + ret =svc_xprt_create (serv,"tcp" , net,PF_INET6 , + nfs_callback_set_tcpport,SVC_SOCK_ANONYMOUS , + cred);if (ret >0 ) { nn->nfs_callback_tcpport6 = ret; dprintk("NFS: Callback listener port = %u (af %u, net %x)\n",
fs/nfsd/nfsctl.c +4 -4
@@ -772,13 +772,13 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct crif (err !=0 )return err; - err =svc_create_xprt (nn->nfsd_serv, transport, net, -PF_INET , port,SVC_SOCK_ANONYMOUS , cred); + err =svc_xprt_create (nn->nfsd_serv, transport, net, +PF_INET , port,SVC_SOCK_ANONYMOUS , cred);if (err <0 ) goto out_err; - err =svc_create_xprt (nn->nfsd_serv, transport, net, -PF_INET6 , port,SVC_SOCK_ANONYMOUS , cred); + err =svc_xprt_create (nn->nfsd_serv, transport, net, +PF_INET6 , port,SVC_SOCK_ANONYMOUS , cred);if (err <0 && err != -EAFNOSUPPORT ) goto out_close;
fs/nfsd/nfssvc.c +4 -4
@@ -293,13 +293,13 @@ static int nfsd_init_socks(struct net *net, const struct cred *cred)if (!list_empty (&nn->nfsd_serv->sv_permsocks))return 0 ; - error =svc_create_xprt (nn->nfsd_serv,"udp" , net,PF_INET ,NFS_PORT , -SVC_SOCK_DEFAULTS , cred); + error =svc_xprt_create (nn->nfsd_serv,"udp" , net,PF_INET ,NFS_PORT , +SVC_SOCK_DEFAULTS , cred);if (error <0 )return error; - error =svc_create_xprt (nn->nfsd_serv,"tcp" , net,PF_INET ,NFS_PORT , -SVC_SOCK_DEFAULTS , cred); + error =svc_xprt_create (nn->nfsd_serv,"tcp" , net,PF_INET ,NFS_PORT , +SVC_SOCK_DEFAULTS , cred);if (error <0 )return error;
include/linux/sunrpc/svc_xprt.h +4 -3
@@ -127,9 +127,10 @@ int svc_reg_xprt_class(struct svc_xprt_class *);void svc_unreg_xprt_class (struct svc_xprt_class *);void svc_xprt_init (struct net *,struct svc_xprt_class *,struct svc_xprt *,struct svc_serv *); -int svc_create_xprt (struct svc_serv *,const char *,struct net *, -const int ,const unsigned short ,int , -const struct cred *); +int svc_xprt_create (struct svc_serv *serv,const char *xprt_name, +struct net *net,const int family, +const unsigned short port,int flags, +const struct cred *cred);void svc_xprt_received (struct svc_xprt *xprt);void svc_xprt_enqueue (struct svc_xprt *xprt);void svc_xprt_put (struct svc_xprt *xprt);
net/sunrpc/svc_xprt.c +19 -5
@@ -272,7 +272,7 @@ void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new)svc_xprt_received (new); } -static int _svc_create_xprt (struct svc_serv *serv,const char *xprt_name, +static int _svc_xprt_create (struct svc_serv *serv,const char *xprt_name,struct net *net,const int family,const unsigned short port,int flags,const struct cred *cred)
@@ -308,21 +308,35 @@ static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name,return -EPROTONOSUPPORT ; } -int svc_create_xprt (struct svc_serv *serv,const char *xprt_name, +/** +* svc_xprt_create - Add a new listener to @serv +* @serv: target RPC service +* @xprt_name: transport class name +* @net: network namespace +* @family: network address family +* @port: listener port +* @flags: SVC_SOCK flags +* @cred: credential to bind to this transport +* +* Return values: +* %0: New listener added successfully +* %-EPROTONOSUPPORT: Requested transport type not supported +*/ +int svc_xprt_create (struct svc_serv *serv,const char *xprt_name,struct net *net,const int family,const unsigned short port,int flags,const struct cred *cred) {int err; - err =_svc_create_xprt (serv, xprt_name, net, family, port, flags, cred); + err =_svc_xprt_create (serv, xprt_name, net, family, port, flags, cred);if (err == -EPROTONOSUPPORT ) {request_module ("svc%s" , xprt_name); - err =_svc_create_xprt (serv, xprt_name, net, family, port, flags, cred); + err =_svc_xprt_create (serv, xprt_name, net, family, port, flags, cred); }return err; } -EXPORT_SYMBOL_GPL (svc_create_xprt); +EXPORT_SYMBOL_GPL (svc_xprt_create);/* * Copy the local and remote xprt addresses to the rqstp structure
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 478/770 SUNRPC: Rename svc_close_xprt()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 4355d767a21b9445958fc11bce9a9701f76529d3 ]
Clean up: Use the "svc_xprt_<task>" function naming convention as is used for other external APIs.
--- fs/nfsd/nfsctl.c | 2 +- include/linux/sunrpc/svc_xprt.h | 2 +- net/sunrpc/svc.c | 2 +- net/sunrpc/svc_xprt.c | 9 +++++++-- net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-)
fs/nfsd/nfsctl.c +1 -1
@@ -790,7 +790,7 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr out_close: xprt =svc_find_xprt (nn->nfsd_serv, transport, net,PF_INET , port);if (xprt !=NULL ) { -svc_close_xprt (xprt); +svc_xprt_close (xprt);svc_xprt_put (xprt); } out_err:
include/linux/sunrpc/svc_xprt.h +1 -1
@@ -135,7 +135,7 @@ void svc_xprt_received(struct svc_xprt *xprt);void svc_xprt_enqueue (struct svc_xprt *xprt);void svc_xprt_put (struct svc_xprt *xprt);void svc_xprt_copy_addrs (struct svc_rqst *rqstp,struct svc_xprt *xprt); -void svc_close_xprt (struct svc_xprt *xprt); +void svc_xprt_close (struct svc_xprt *xprt);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,
net/sunrpc/svc.c +1 -1
@@ -1403,7 +1403,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)svc_authorise (rqstp); close_xprt:if (rqstp->rq_xprt &&test_bit (XPT_TEMP , &rqstp->rq_xprt->xpt_flags)) -svc_close_xprt (rqstp->rq_xprt); +svc_xprt_close (rqstp->rq_xprt);dprintk ("svc: svc_process close\n" );return 0 ;
net/sunrpc/svc_xprt.c +7 -2
@@ -1056,7 +1056,12 @@ static void svc_delete_xprt(struct svc_xprt *xprt)svc_xprt_put (xprt); } -void svc_close_xprt (struct svc_xprt *xprt) +/** +* svc_xprt_close - Close a client connection +* @xprt: transport to disconnect +* +*/ +void svc_xprt_close (struct svc_xprt *xprt) {trace_svc_xprt_close (xprt);set_bit (XPT_CLOSE , &xprt->xpt_flags);
@@ -1071,7 +1076,7 @@ void svc_close_xprt(struct svc_xprt *xprt)*/ svc_delete_xprt (xprt); } -EXPORT_SYMBOL_GPL (svc_close_xprt); +EXPORT_SYMBOL_GPL (svc_xprt_close);static int svc_close_list (struct svc_serv *serv,struct list_head *xprt_list,struct net *net) {
net/sunrpc/xprtrdma/svc_rdma_backchannel.c +1 -1
@@ -186,7 +186,7 @@ static int xprt_rdma_bc_send_request(struct rpc_rqst *rqst) ret =rpcrdma_bc_send_request (rdma, rqst);if (ret == -ENOTCONN ) -svc_close_xprt (sxprt); +svc_xprt_close (sxprt);return ret; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 479/770 SUNRPC: Remove svc_shutdown_net()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit c7d7ec8f043e53ad16e30f5ebb8b9df415ec0f2b ]
Clean up: svc_shutdown_net() now does nothing but call svc_close_net(). Replace all external call sites.
svc_close_net() is renamed to be the inverse of svc_xprt_create().
--- fs/lockd/svc.c | 4 ++-- fs/nfs/callback.c | 2 +- fs/nfsd/nfssvc.c | 2 +- include/linux/sunrpc/svc.h | 1 - include/linux/sunrpc/svc_xprt.h | 1 + net/sunrpc/svc.c | 6 ------ net/sunrpc/svc_xprt.c | 9 +++++++-- 7 files changed, 12 insertions(+), 13 deletions(-)
fs/lockd/svc.c +2 -2
@@ -248,7 +248,7 @@ static int make_socks(struct svc_serv *serv, struct net *net,if (warned++ ==0 )printk (KERN_WARNING "lockd_up: makesock failed, error=%d\n" , err); -svc_shutdown_net (serv, net); +svc_xprt_destroy_all (serv, net);svc_rpcb_cleanup (serv, net);return err; }
@@ -287,7 +287,7 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net)nlm_shutdown_hosts_net (net);cancel_delayed_work_sync (&ln->grace_period_end);locks_end_grace (&ln->lockd_manager); -svc_shutdown_net (serv, net); +svc_xprt_destroy_all (serv, net);svc_rpcb_cleanup (serv, net); } }else {
fs/nfs/callback.c +1 -1
@@ -189,7 +189,7 @@ static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, strucreturn ;dprintk ("NFS: destroy per-net callback data; net=%x\n" , net->ns.inum); -svc_shutdown_net (serv, net); +svc_xprt_destroy_all (serv, net); } static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
fs/nfsd/nfssvc.c +1 -1
@@ -722,7 +722,7 @@ void nfsd_put(struct net *net)struct nfsd_net *nn =net_generic (net, nfsd_net_id);if (kref_put (&nn->nfsd_serv->sv_refcnt, nfsd_noop)) { -svc_shutdown_net (nn->nfsd_serv, net); +svc_xprt_destroy_all (nn->nfsd_serv, net);nfsd_last_thread (nn->nfsd_serv, net);svc_destroy (&nn->nfsd_serv->sv_refcnt);spin_lock (&nfsd_notifier_lock);
include/linux/sunrpc/svc.h +0 -1
@@ -511,7 +511,6 @@ struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, const struct svc_serv_ops *); int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);int svc_pool_stats_open (struct svc_serv *serv,struct file *file); -void svc_shutdown_net (struct svc_serv *,struct net *);int svc_process (struct svc_rqst *);int bc_svc_process (struct svc_serv *,struct rpc_rqst *,struct svc_rqst *);
include/linux/sunrpc/svc_xprt.h +1 -0
@@ -131,6 +131,7 @@ int svc_xprt_create(struct svc_serv *serv, const char *xprt_name, struct net *net, const int family, const unsigned short port, int flags, const struct cred *cred); +void svc_xprt_destroy_all (struct svc_serv *serv,struct net *net);void svc_xprt_received (struct svc_xprt *xprt);void svc_xprt_enqueue (struct svc_xprt *xprt);void svc_xprt_put (struct svc_xprt *xprt);
net/sunrpc/svc.c +0 -6
@@ -534,12 +534,6 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, }EXPORT_SYMBOL_GPL (svc_create_pooled); -void svc_shutdown_net (struct svc_serv *serv,struct net *net) -{ -svc_close_net (serv, net); -} -EXPORT_SYMBOL_GPL (svc_shutdown_net); -/* * Destroy an RPC service. Should be called with appropriate locking to * protect sv_permsocks and sv_tempsocks.
net/sunrpc/svc_xprt.c +7 -2
@@ -1128,7 +1128,11 @@ static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net) } } -/* +/** +* svc_xprt_destroy_all - Destroy transports associated with @serv +* @serv: RPC service to be shut down +* @net: target network namespace +* * Server threads may still be running (especially in the case where the * service is still running in other network namespaces). *
@@ -1140,7 +1144,7 @@ static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net)* threads, we may need to wait a little while and then check again to * see if they're done. */ -void svc_close_net (struct svc_serv *serv,struct net *net) +void svc_xprt_destroy_all (struct svc_serv *serv,struct net *net) {int delay =0 ;
@@ -1151,6 +1155,7 @@ void svc_close_net(struct svc_serv *serv, struct net *net)msleep (delay++); } } +EXPORT_SYMBOL_GPL (svc_xprt_destroy_all);/* * Handle defer and revisit of requests
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 480/770 NFSD: Remove svc_serv_ops::svo_module
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit f49169c97fceb21ad6a0aaf671c50b0f520f15a5 ]
struct svc_serv_ops is about to be removed.
Neil Brown says:
Quoted 2 lines
I suspect
svo_modulecan go as well - I don't think the thread is ever the thing that primarily keeps a module active.
A random sample of kthread_create() callers shows sunrpc is the only one that manages module reference count in this way.
--- fs/lockd/svc.c | 4 +--- fs/nfs/callback.c | 7 ++----- fs/nfs/nfs4state.c | 1 - fs/nfsd/nfssvc.c | 3 --- include/linux/sunrpc/svc.h | 5 ----- kernel/module.c | 2 +- net/sunrpc/svc.c | 2 -- 7 files changed, 4 insertions(+), 20 deletions(-)
fs/lockd/svc.c +1 -3
@@ -184,8 +184,7 @@ lockd(void *vrqstp)dprintk ("lockd_down: service stopped\n" );svc_exit_thread (rqstp); - -module_put_and_kthread_exit (0 ); +return 0 ; } static int create_lockd_listener(struct svc_serv *serv, const char *name,
@@ -352,7 +351,6 @@ static struct notifier_block lockd_inet6addr_notifier = {static const struct svc_serv_ops lockd_sv_ops = { .svo_function = lockd, - .svo_module =THIS_MODULE , };static int lockd_get (void )
fs/nfs/callback.c +2 -5
@@ -17,7 +17,6 @@#include <linux/errno.h> #include <linux/mutex.h> #include <linux/freezer.h> -#include <linux/kthread.h> #include <linux/sunrpc/svcauth_gss.h> #include <linux/sunrpc/bc_xprt.h>
@@ -92,8 +91,8 @@ nfs4_callback_svc(void *vrqstp)continue ;svc_process (rqstp); } +svc_exit_thread (rqstp); -module_put_and_kthread_exit (0 );return 0 ; }
@@ -136,8 +135,8 @@ nfs41_callback_svc(void *vrqstp)finish_wait (&serv->sv_cb_waitq, &wq); } } +svc_exit_thread (rqstp); -module_put_and_kthread_exit (0 );return 0 ; }
@@ -234,12 +233,10 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,static const struct svc_serv_ops nfs40_cb_sv_ops = { .svo_function = nfs4_callback_svc, - .svo_module =THIS_MODULE , };#if defined(CONFIG_NFS_V4_1 )static const struct svc_serv_ops nfs41_cb_sv_ops = { .svo_function = nfs41_callback_svc, - .svo_module =THIS_MODULE , }; static const struct svc_serv_ops *nfs4_cb_sv_ops[] = {
fs/nfs/nfs4state.c +0 -1
@@ -2757,7 +2757,6 @@ static int nfs4_run_state_manager(void *ptr) goto again;nfs_put_client (clp); -module_put_and_kthread_exit (0 );return 0 ; }
fs/nfsd/nfssvc.c +0 -3
@@ -614,7 +614,6 @@ static int nfsd_get_default_max_blksize(void)static const struct svc_serv_ops nfsd_thread_sv_ops = { .svo_function = nfsd, - .svo_module =THIS_MODULE , };void nfsd_shutdown_threads (struct net *net)
@@ -1018,8 +1017,6 @@ nfsd(void *vrqstp)msleep (20 ); } -/* Release module */ -module_put_and_kthread_exit (0 );return 0 ; }
include/linux/sunrpc/svc.h +0 -5
@@ -57,11 +57,6 @@ struct svc_serv;struct svc_serv_ops {/* function for service threads to run */ int (*svo_function)(void *); - -/* optional module to count when adding threads. -* Thread function must call module_put_and_kthread_exit() to exit. -*/ -struct module *svo_module; };/*
kernel/module.c +1 -1
@@ -334,7 +334,7 @@ static inline void add_taint_module(struct module *mod, unsigned flag,/* * A thread that wants to hold a reference to a module only while it -* is running can call this to safely exit. nfsd and lockd use this. +* is running can call this to safely exit. */ void __noreturn __module_put_and_kthread_exit (struct module *mod,long code) {
net/sunrpc/svc.c +0 -2
@@ -734,11 +734,9 @@ svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)if (IS_ERR (rqstp))return PTR_ERR (rqstp); -__module_get (serv->sv_ops->svo_module); task =kthread_create_on_node (serv->sv_ops->svo_function, rqstp, node,"%s" , serv->sv_name);if (IS_ERR (task)) { -module_put (serv->sv_ops->svo_module);svc_exit_thread (rqstp);return PTR_ERR (task); }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 481/770 NFSD: Move svc_serv_ops::svo_function into struct svc_serv
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 37902c6313090235c847af89c5515591261ee338 ]
Hoist svo_function back into svc_serv and remove struct svc_serv_ops, since the struct is now devoid of fields.
--- fs/lockd/svc.c | 6 +----- fs/nfs/callback.c | 43 ++++++++++---------------------------- fs/nfsd/nfssvc.c | 7 +------ include/linux/sunrpc/svc.h | 14 ++++--------- net/sunrpc/svc.c | 37 ++++++++++++++++++++++---------- 5 files changed, 43 insertions(+), 64 deletions(-)
fs/lockd/svc.c +1 -5
@@ -349,10 +349,6 @@ static struct notifier_block lockd_inet6addr_notifier = { };#endif -static const struct svc_serv_ops lockd_sv_ops = { - .svo_function = lockd, -}; -static int lockd_get (void ) {struct svc_serv *serv;
@@ -376,7 +372,7 @@ static int lockd_get(void) nlm_timeout =LOCKD_DFLT_TIMEO ; nlmsvc_timeout = nlm_timeout *HZ ; - serv =svc_create (&nlmsvc_program,LOCKD_BUFSIZE , &lockd_sv_ops); + serv =svc_create (&nlmsvc_program,LOCKD_BUFSIZE , lockd);if (!serv) {printk (KERN_WARNING "lockd_up: create service failed\n" );return -ENOMEM ;
fs/nfs/callback.c +11 -32
64 lines not on this page · raw message
fs/nfsd/nfssvc.c +1 -6
@@ -612,10 +612,6 @@ static int nfsd_get_default_max_blksize(void)return ret; } -static const struct svc_serv_ops nfsd_thread_sv_ops = { - .svo_function = nfsd, -}; -void nfsd_shutdown_threads (struct net *net) {struct nfsd_net *nn =net_generic (net, nfsd_net_id);
@@ -654,8 +650,7 @@ int nfsd_create_serv(struct net *net)if (nfsd_max_blksize ==0 ) nfsd_max_blksize =nfsd_get_default_max_blksize ();nfsd_reset_versions (nn); - serv =svc_create_pooled (&nfsd_program, nfsd_max_blksize, - &nfsd_thread_sv_ops); + serv =svc_create_pooled (&nfsd_program, nfsd_max_blksize, nfsd);if (serv ==NULL )return -ENOMEM ;
include/linux/sunrpc/svc.h +4 -10
@@ -52,13 +52,6 @@ struct svc_pool {unsigned long sp_flags; }____cacheline_aligned_in_smp ; -struct svc_serv ; - -struct svc_serv_ops { -/* function for service threads to run */ -int (*svo_function)(void *); -}; -/* * RPC service. *
@@ -91,7 +84,8 @@ struct svc_serv {unsigned int sv_nrpools;/* number of thread pools */ struct svc_pool * sv_pools;/* array of thread pools */ -const struct svc_serv_ops *sv_ops;/* server operations */ +int (*sv_threadfn)(void *data); +#if defined(CONFIG_SUNRPC_BACKCHANNEL )struct list_head sv_cb_list;/* queue for callback requests * that arrive over the same
@@ -495,7 +489,7 @@ int svc_rpcb_setup(struct svc_serv *serv, struct net *net);void svc_rpcb_cleanup (struct svc_serv *serv,struct net *net);int svc_bind (struct svc_serv *serv,struct net *net);struct svc_serv *svc_create (struct svc_program *,unsigned int , -const struct svc_serv_ops *); +int (*threadfn)(void *data));struct svc_rqst *svc_rqst_alloc (struct svc_serv *serv,struct svc_pool *pool,int node); void svc_rqst_replace_page(struct svc_rqst *rqstp,
@@ -503,7 +497,7 @@ void svc_rqst_replace_page(struct svc_rqst *rqstp,void svc_rqst_free (struct svc_rqst *);void svc_exit_thread (struct svc_rqst *);struct svc_serv *svc_create_pooled (struct svc_program *,unsigned int , -const struct svc_serv_ops *); +int (*threadfn)(void *data));int svc_set_num_threads (struct svc_serv *,struct svc_pool *,int );int svc_pool_stats_open (struct svc_serv *serv,struct file *file);int svc_process (struct svc_rqst *);
net/sunrpc/svc.c +26 -11
@@ -446,7 +446,7 @@ __svc_init_bc(struct svc_serv *serv)*/ static struct svc_serv *__svc_create (struct svc_program *prog,unsigned int bufsize,int npools, -const struct svc_serv_ops *ops) +int (*threadfn)(void *data)) {struct svc_serv *serv;unsigned int vers;
@@ -463,7 +463,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, bufsize =RPCSVC_MAXPAYLOAD ; serv->sv_max_payload = bufsize? bufsize :4096 ; serv->sv_max_mesg =roundup (serv->sv_max_payload +PAGE_SIZE ,PAGE_SIZE ); - serv->sv_ops = ops; + serv->sv_threadfn = threadfn; xdrsize =0 ;while (prog) { prog->pg_lovers = prog->pg_nvers-1 ;
@@ -509,22 +509,37 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,return serv; } -struct svc_serv * -svc_create (struct svc_program *prog,unsigned int bufsize, -const struct svc_serv_ops *ops) +/** +* svc_create - Create an RPC service +* @prog: the RPC program the new service will handle +* @bufsize: maximum message size for @prog +* @threadfn: a function to service RPC requests for @prog +* +* Returns an instantiated struct svc_serv object or NULL. +*/ +struct svc_serv *svc_create (struct svc_program *prog,unsigned int bufsize, +int (*threadfn)(void *data)) { -return __svc_create (prog, bufsize,/*npools*/ 1 , ops); +return __svc_create (prog, bufsize,1 , threadfn); }EXPORT_SYMBOL_GPL (svc_create); -struct svc_serv * -svc_create_pooled (struct svc_program *prog,unsigned int bufsize, -const struct svc_serv_ops *ops) +/** +* svc_create_pooled - Create an RPC service with pooled threads +* @prog: the RPC program the new service will handle +* @bufsize: maximum message size for @prog +* @threadfn: a function to service RPC requests for @prog +* +* Returns an instantiated struct svc_serv object or NULL. +*/ +struct svc_serv *svc_create_pooled (struct svc_program *prog, +unsigned int bufsize, +int (*threadfn)(void *data)) {struct svc_serv *serv;unsigned int npools =svc_pool_map_get (); - serv =__svc_create (prog, bufsize, npools, ops); + serv =__svc_create (prog, bufsize, npools, threadfn);if (!serv) goto out_err;return serv;
@@ -734,7 +749,7 @@ svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)if (IS_ERR (rqstp))return PTR_ERR (rqstp); - task =kthread_create_on_node (serv->sv_ops->svo_function, rqstp, + task =kthread_create_on_node (serv->sv_threadfn, rqstp, node,"%s" , serv->sv_name);if (IS_ERR (task)) {svc_exit_thread (rqstp);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 482/770 NFSD: Remove CONFIG_NFSD_V3
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 5f9a62ff7d2808c7b56c0ec90f3b7eae5872afe6 ]
Eventually support for NFSv2 in the Linux NFS server is to be deprecated and then removed.
However, NFSv2 is the "always supported" version that is available as soon as CONFIG_NFSD is set. Before NFSv2 support can be removed, we need to choose a different "always supported" version.
This patch removes CONFIG_NFSD_V3 so that NFSv3 is always supported, as NFSv2 is today. When NFSv2 support is removed, NFSv3 will become the only "always supported" NFS version.
The defconfigs still need to be updated to remove CONFIG_NFSD_V3=y.
--- fs/Kconfig | 2 +- fs/nfsd/Kconfig | 12 +----------- fs/nfsd/Makefile | 3 +-- fs/nfsd/nfsfh.c | 4 ---- fs/nfsd/nfsfh.h | 20 -------------------- fs/nfsd/nfssvc.c | 2 -- fs/nfsd/vfs.c | 9 --------- fs/nfsd/vfs.h | 2 -- 8 files changed, 3 insertions(+), 51 deletions(-)
fs/Kconfig +1 -1
@@ -320,7 +320,7 @@ config LOCKD config LOCKD_V4 bool - depends on NFSD_V3 || NFS_V3 + depends on NFSD || NFS_V3 depends on FILE_LOCKING default y
fs/nfsd/Kconfig +1 -11
@@ -35,18 +35,9 @@ config NFSD_V2_ACL bool depends on NFSD -config NFSD_V3 - bool "NFS server support for NFS version 3" - depends on NFSD - help - This option enables support in your system's NFS server for - version 3 of the NFS protocol (RFC 1813). - - If unsure, say Y. - config NFSD_V3_ACL bool "NFS server support for the NFSv3 ACL protocol extension" - depends on NFSD_V3 + depends on NFSD select NFSD_V2_ACL help Solaris NFS servers support an auxiliary NFSv3 ACL protocol that
@@ -70,7 +61,6 @@ config NFSD_V3_ACL config NFSD_V4 bool "NFS server support for NFS version 4" depends on NFSD && PROC_FS - select NFSD_V3 select FS_POSIX_ACL select SUNRPC_GSS select CRYPTO
fs/nfsd/Makefile +1 -2
@@ -12,9 +12,8 @@ nfsd-y += trace.o nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ export.o auth.o lockd.o nfscache.o nfsxdr.o \ - stats.o filecache.o + stats.o filecache.o nfs3proc.o nfs3xdr.o nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o -nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ nfs4acl.o nfs4callback.o nfs4recover.o
fs/nfsd/nfsfh.c +0 -4
@@ -610,8 +610,6 @@ fh_update(struct svc_fh *fhp)return nfserr_serverfault; } -#ifdef CONFIG_NFSD_V3 -/** * fh_fill_pre_attrs - Fill in pre-op attributes * @fhp: file handle to be updated
@@ -672,8 +670,6 @@ void fh_fill_post_attrs(struct svc_fh *fhp)nfsd4_change_attribute (&fhp->fh_post_attr, inode); } -#endif /* CONFIG_NFSD_V3 */ -/* * Release a file handle. */
fs/nfsd/nfsfh.h +0 -20
@@ -90,7 +90,6 @@ typedef struct svc_fh {* operation */ int fh_flags;/* FH flags */ -#ifdef CONFIG_NFSD_V3 bool fh_post_saved;/* post-op attrs saved */ bool fh_pre_saved;/* pre-op attrs saved */
@@ -107,7 +106,6 @@ typedef struct svc_fh {/* 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;#define NFSD4_FH_FOREIGN (1<<0)#define SET_FH_FLAG (c, f) ((c)->fh_flags |= (f))
@@ -283,8 +281,6 @@ static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) }#endif -#ifdef CONFIG_NFSD_V3 -/** * fh_clear_pre_post_attrs - Reset pre/post attributes * @fhp: file handle to be updated
@@ -327,22 +323,6 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,extern void fh_fill_pre_attrs (struct svc_fh *fhp);extern void fh_fill_post_attrs (struct svc_fh *fhp); -#else /* !CONFIG_NFSD_V3 */ - -static inline void fh_clear_pre_post_attrs (struct svc_fh *fhp) -{ -} - -static inline void fh_fill_pre_attrs (struct svc_fh *fhp) -{ -} - -static inline void fh_fill_post_attrs (struct svc_fh *fhp) -{ -} - -#endif /* !CONFIG_NFSD_V3 */ -/* * Lock a file handle/inode
fs/nfsd/nfssvc.c +0 -2
@@ -117,9 +117,7 @@ static struct svc_stat nfsd_acl_svcstats = {static const struct svc_version *nfsd_version[] = { [2 ] = &nfsd_version2, -#if defined(CONFIG_NFSD_V3) [3 ] = &nfsd_version3, -#endif #if defined(CONFIG_NFSD_V4) [4 ] = &nfsd_version4, #endif
fs/nfsd/vfs.c +0 -9
@@ -32,9 +32,7 @@#include <linux/writeback.h> #include <linux/security.h> -#ifdef CONFIG_NFSD_V3 #include "xdr3.h" -#endif /* CONFIG_NFSD_V3 */ #ifdef CONFIG_NFSD_V4 #include "../internal.h"
@@ -627,7 +625,6 @@ __be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp, }#endif /* defined(CONFIG_NFSD_V4) */ -#ifdef CONFIG_NFSD_V3 /* * Check server access rights to a file system object */
@@ -739,7 +736,6 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor out:return error; } -#endif /* CONFIG_NFSD_V3 */ int nfsd_open_break_lease (struct inode *inode,int access) {
@@ -1139,7 +1135,6 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,return err; } -#ifdef CONFIG_NFSD_V3 /** * nfsd_commit - Commit pending writes to stable storage * @rqstp: RPC request being processed
@@ -1217,7 +1212,6 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset, out:return err; } -#endif /* CONFIG_NFSD_V3 */ static __be32 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
@@ -1406,8 +1400,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, rdev, resfhp); } -#ifdef CONFIG_NFSD_V3 -/* * NFSv3 and NFSv4 version of nfsd_create */
@@ -1573,7 +1565,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, err =nfserrno (host_err); goto out; } -#endif /* CONFIG_NFSD_V3 */ /* * Read a symlink. On entry, *lenp must contain the maximum path length that
fs/nfsd/vfs.h +0 -2
@@ -68,7 +68,6 @@ __be32 nfsd_create_locked(struct svc_rqst *, struct svc_fh *,__be32 nfsd_create (struct svc_rqst *,struct svc_fh *,char *name,int len,struct iattr *attrs,int type,dev_t rdev,struct svc_fh *res); -#ifdef CONFIG_NFSD_V3 __be32 nfsd_access (struct svc_rqst *,struct svc_fh *,u32 *,u32 *); __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs,
@@ -76,7 +75,6 @@ __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, u32 *verifier, bool *truncp, bool *created);__be32 nfsd_commit (struct svc_rqst *rqst,struct svc_fh *fhp,u64 offset,u32 count,__be32 *verf); -#endif /* CONFIG_NFSD_V3 */ #ifdef CONFIG_NFSD_V4 __be32 nfsd_getxattr (struct svc_rqst *rqstp,struct svc_fh *fhp,char *name,void **bufp,int *lenp);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 483/770 NFSD: Clean up _lm_ operation names
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 35aff0678f99b0623bb72d50112de9e163a19559 ]
The common practice is to name function instances the same as the method names, but with a uniquifying prefix. Commit aef9583b234a ("NFSD: Get reference of lockowner when coping file_lock") missed this -- the new function names should both have been of the form "nfsd4_lm_*".
Before more lock manager operations are added in NFSD, rename these two functions for consistency.
--- fs/nfsd/nfs4state.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +4 -4
@@ -6566,7 +6566,7 @@ nfs4_transform_lock_offset(struct file_lock *lock) }static fl_owner_t -nfsd4_fl_get_owner (fl_owner_t owner) +nfsd4_lm_get_owner (fl_owner_t owner) {struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner;
@@ -6575,7 +6575,7 @@ nfsd4_fl_get_owner(fl_owner_t owner) }static void -nfsd4_fl_put_owner (fl_owner_t owner) +nfsd4_lm_put_owner (fl_owner_t owner) {struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner;
@@ -6610,8 +6610,8 @@ nfsd4_lm_notify(struct file_lock *fl)static const struct lock_manager_operations nfsd_posix_mng_ops = { .lm_notify = nfsd4_lm_notify, - .lm_get_owner = nfsd4_fl_get_owner, - .lm_put_owner = nfsd4_fl_put_owner, + .lm_get_owner = nfsd4_lm_get_owner, + .lm_put_owner = nfsd4_lm_put_owner, }; static inline void
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 484/770 nfsd: fix using the correct variable for sizeof()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakob Koschel <[email protected]>
[ Upstream commit 4fc5f5346592cdc91689455d83885b0af65d71b8 ]
While the original code is valid, it is not the obvious choice for the sizeof() call and in preparation to limit the scope of the list iterator variable the sizeof should be changed to the size of the destination.
--- fs/nfsd/nfs4layouts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfs4layouts.c +1 -1
@@ -421,7 +421,7 @@ nfsd4_insert_layout(struct nfsd4_layoutget *lgp, struct nfs4_layout_stateid *ls) new =kmem_cache_alloc (nfs4_layout_cache,GFP_KERNEL );if (!new)return nfserr_jukebox; -memcpy (&new->lo_seg, seg,sizeof (lp->lo_seg)); +memcpy (&new->lo_seg, seg,sizeof (new->lo_seg)); new->lo_state = ls;spin_lock (&fp->fi_lock);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 485/770 fsnotify: fix merge with parents ignored mask
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 4f0b903ded728c505850daf2914bfc08841f0ae6 ]
fsnotify_parent() does not consider the parent's mark at all unless the parent inode shows interest in events on children and in the specific event.
So unless parent added an event to both its mark mask and ignored mask, the event will not be ignored.
Fix this by declaring the interest of an object in an event when the event is in either a mark mask or ignored mask.
--- fs/notify/fanotify/fanotify_user.c | 17 +++++++++-------- fs/notify/mark.c | 4 ++-- include/linux/fsnotify_backend.h | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 10 deletions(-)
fs/notify/fanotify/fanotify_user.c +9 -8
@@ -991,17 +991,18 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, __u32 mask, unsigned int flags, __u32 umask, int *destroy) { - __u32 oldmask = 0; + __u32 oldmask, newmask;/* umask bits cannot be removed by user */ mask &= ~umask;spin_lock (&fsn_mark->lock); + oldmask =fsnotify_calc_mask (fsn_mark);if (!(flags &FAN_MARK_IGNORED_MASK )) { - oldmask = fsn_mark->mask; fsn_mark->mask &= ~mask; }else { fsn_mark->ignored_mask &= ~mask; } + newmask =fsnotify_calc_mask (fsn_mark);/* * We need to keep the mark around even if remaining mask cannot * result in any events (e.g. mask == FAN_ONDIR) to support incremenal
@@ -1011,7 +1012,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, *destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask);spin_unlock (&fsn_mark->lock); -return mask & oldmask; +return oldmask & ~newmask; } static int fanotify_remove_mark(struct fsnotify_group *group,
@@ -1069,23 +1070,23 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, }static __u32 fanotify_mark_add_to_mask (struct fsnotify_mark *fsn_mark, -__u32 mask, -unsigned int flags) +__u32 mask,unsigned int flags) { -__u32 oldmask =-1 ; +__u32 oldmask, newmask;spin_lock (&fsn_mark->lock); + oldmask =fsnotify_calc_mask (fsn_mark);if (!(flags &FAN_MARK_IGNORED_MASK )) { - oldmask = fsn_mark->mask; fsn_mark->mask |= mask; }else { fsn_mark->ignored_mask |= mask;if (flags &FAN_MARK_IGNORED_SURV_MODIFY ) fsn_mark->flags |=FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ; } + newmask =fsnotify_calc_mask (fsn_mark);spin_unlock (&fsn_mark->lock); -return mask & ~oldmask; +return newmask & ~oldmask; } static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
fs/notify/mark.c +2 -2
@@ -127,7 +127,7 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)return ;hlist_for_each_entry (mark, &conn->list, obj_list) {if (mark->flags &FSNOTIFY_MARK_FLAG_ATTACHED ) - new_mask |= mark->mask; + new_mask |=fsnotify_calc_mask (mark); } *fsnotify_conn_mask_p (conn) = new_mask; }
@@ -692,7 +692,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,if (ret) goto err; -if (mark->mask) +if (mark->mask || mark->ignored_mask)fsnotify_recalc_mask (mark->connector);return ret;
include/linux/fsnotify_backend.h +15 -0
@@ -601,6 +601,21 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group,/* functions used to manipulate the marks attached to inodes */ +/* Get mask for calculating object interest taking ignored mask into account */ +static inline __u32 fsnotify_calc_mask (struct fsnotify_mark *mark) +{ +__u32 mask = mark->mask; + +if (!mark->ignored_mask) +return mask; + +/* +* If mark is interested in ignoring events on children, the object must +* show interest in those events for fsnotify_parent() to notice it. +*/ +return mask | (mark->ignored_mask &ALL_FSNOTIFY_EVENTS ); +} +/* Get mask of events for a list of marks */ extern __u32 fsnotify_conn_mask (struct fsnotify_mark_connector *conn);/* Calculate mask of events for a list of marks */
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 486/770 fsnotify: optimize FS_MODIFY events with no ignored masks
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 04e317ba72d07901b03399b3d1525e83424df5b3 ]
fsnotify() treats FS_MODIFY events specially - it does not skip them even if the FS_MODIFY event does not apear in the object's fsnotify mask. This is because send_to_group() checks if FS_MODIFY needs to clear ignored mask of marks.
The common case is that an object does not have any mark with ignored mask and in particular, that it does not have a mark with ignored mask and without the FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY flag.
Set FS_MODIFY in object's fsnotify mask during fsnotify_recalc_mask() if object has a mark with an ignored mask and without the FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY flag and remove the special treatment of FS_MODIFY in fsnotify(), so that FS_MODIFY events could be optimized in the common case.
Call fsnotify_recalc_mask() from fanotify after adding or removing an ignored mask from a mark without FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY or when adding the FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY flag to a mark with ignored mask (the flag cannot be removed by fanotify uapi).
Performance results for doing 10000000 write(2)s to tmpfs:
vanilla patched
without notification mark 25.486+-1.054 24.965+-0.244
with notification mark 30.111+-0.139 26.891+-1.355
So we can see the overhead of notification subsystem has been drastically reduced.
--- fs/notify/fanotify/fanotify_user.c | 32 +++++++++++++++++++++++------- fs/notify/fsnotify.c | 8 +++++--- include/linux/fsnotify_backend.h | 4 ++++ 3 files changed, 34 insertions(+), 10 deletions(-)
fs/notify/fanotify/fanotify_user.c +25 -7
@@ -1069,8 +1069,28 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, flags, umask); } +static void fanotify_mark_add_ignored_mask (struct fsnotify_mark *fsn_mark, +__u32 mask,unsigned int flags, +__u32 *removed) +{ + fsn_mark->ignored_mask |= mask; + +/* +* Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to +* the removal of the FS_MODIFY bit in calculated mask if it was set +* because of an ignored mask that is now going to survive FS_MODIFY. +*/ +if ((flags &FAN_MARK_IGNORED_SURV_MODIFY ) && + !(fsn_mark->flags &FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY )) { + fsn_mark->flags |=FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ; +if (!(fsn_mark->mask &FS_MODIFY )) + *removed =FS_MODIFY ; + } +} +static __u32 fanotify_mark_add_to_mask (struct fsnotify_mark *fsn_mark, -__u32 mask,unsigned int flags) +__u32 mask,unsigned int flags, +__u32 *removed) {__u32 oldmask, newmask;
@@ -1079,9 +1099,7 @@ static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,if (!(flags &FAN_MARK_IGNORED_MASK )) { fsn_mark->mask |= mask; }else { - fsn_mark->ignored_mask |= mask; -if (flags &FAN_MARK_IGNORED_SURV_MODIFY ) - fsn_mark->flags |=FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ; +fanotify_mark_add_ignored_mask (fsn_mark, mask, flags, removed); } newmask =fsnotify_calc_mask (fsn_mark);spin_unlock (&fsn_mark->lock);
@@ -1144,7 +1162,7 @@ static int fanotify_add_mark(struct fsnotify_group *group, __kernel_fsid_t *fsid) {struct fsnotify_mark *fsn_mark; -__u32 added; +__u32 added, removed =0 ;int ret =0 ;mutex_lock (&group->mark_mutex);
@@ -1167,8 +1185,8 @@ static int fanotify_add_mark(struct fsnotify_group *group, goto out; } - added =fanotify_mark_add_to_mask (fsn_mark, mask, flags); -if (added & ~fsnotify_conn_mask (fsn_mark->connector)) + added =fanotify_mark_add_to_mask (fsn_mark, mask, flags, &removed); +if (removed || (added & ~fsnotify_conn_mask (fsn_mark->connector)))fsnotify_recalc_mask (fsn_mark->connector); out:
fs/notify/fsnotify.c +5 -3
@@ -531,11 +531,13 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,/* -* if this is a modify event we may need to clear the ignored masks -* otherwise return if none of the marks care about this type of event. +* If this is a modify event we may need to clear some ignored masks. +* In that case, the object with ignored masks will have the FS_MODIFY +* event in its mask. +* Otherwise, return if none of the marks care about this type of event. */ test_mask = (mask &ALL_FSNOTIFY_EVENTS ); -if (!(mask &FS_MODIFY ) && !(test_mask & marks_mask)) +if (!(test_mask & marks_mask))return 0 ; iter_info.srcu_idx =srcu_read_lock (&fsnotify_mark_srcu);
include/linux/fsnotify_backend.h +4 -0
@@ -609,6 +609,10 @@ static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)if (!mark->ignored_mask)return mask; +/* Interest in FS_MODIFY may be needed for clearing ignored mask */ +if (!(mark->flags &FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY )) + mask |=FS_MODIFY ; +/* * If mark is interested in ignoring events on children, the object must * show interest in those events for fsnotify_parent() to notice it.
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 487/770 fsnotify: remove redundant parameter judgment
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bang Li <[email protected]>
[ Upstream commit f92ca72b0263d601807bbd23ed25cbe6f4da89f4 ]
iput() has already judged the incoming parameter, so there is no need to repeat the judgment here.
--- fs/notify/fsnotify.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
fs/notify/fsnotify.c +2 -4
@@ -70,8 +70,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb)spin_unlock (&inode->i_lock);spin_unlock (&sb->s_inode_list_lock); -if (iput_inode) -iput (iput_inode); +iput (iput_inode);/* for each watch, send FS_UNMOUNT and then remove it */ fsnotify_inode (inode,FS_UNMOUNT );
@@ -85,8 +84,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb) }spin_unlock (&sb->s_inode_list_lock); -if (iput_inode) -iput (iput_inode); +iput (iput_inode); }void fsnotify_sb_delete (struct super_block *sb)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 488/770 SUNRPC: Return true/false (not 1/0) from bool functions
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haowen Bai <[email protected]>
[ Upstream commit 5f7b839d47dbc74cf4a07beeab5191f93678673e ]
Return boolean values ("true" or "false") instead of 1 or 0 from bool functions. This fixes the following warnings from coccicheck:
./fs/nfsd/nfs2acl.c:289:9-10: WARNING: return of 0/1 in function 'nfsaclsvc_encode_accessres' with return type bool ./fs/nfsd/nfs2acl.c:252:9-10: WARNING: return of 0/1 in function 'nfsaclsvc_encode_getaclres' with return type bool
--- fs/nfsd/nfs2acl.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
fs/nfsd/nfs2acl.c +12 -12
@@ -247,34 +247,34 @@ nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)int w;if (!svcxdr_encode_stat (xdr, resp->status)) -return 0 ; +return false;if (dentry ==NULL ||d_really_is_negative (dentry)) -return 1 ; +return true; inode =d_inode (dentry);if (!svcxdr_encode_fattr (rqstp, xdr, &resp->fh, &resp->stat)) -return 0 ; +return false;if (xdr_stream_encode_u32 (xdr, resp->mask) <0 ) -return 0 ; +return false; rqstp->rq_res.page_len = w =nfsacl_size ( (resp->mask &NFS_ACL ) ? resp->acl_access :NULL , (resp->mask &NFS_DFACL ) ? resp->acl_default :NULL );while (w >0 ) {if (!*(rqstp->rq_next_page++)) -return 1 ; +return true; w -=PAGE_SIZE ; }if (!nfs_stream_encode_acl (xdr, inode, resp->acl_access, resp->mask &NFS_ACL ,0 )) -return 0 ; +return false;if (!nfs_stream_encode_acl (xdr, inode, resp->acl_default, resp->mask &NFS_DFACL ,NFS_ACL_DEFAULT )) -return 0 ; +return false; -return 1 ; +return true; }/* ACCESS */
@@ -284,17 +284,17 @@ nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr)struct nfsd3_accessres *resp = rqstp->rq_resp;if (!svcxdr_encode_stat (xdr, resp->status)) -return 0 ; +return false;switch (resp->status) {case nfs_ok:if (!svcxdr_encode_fattr (rqstp, xdr, &resp->fh, &resp->stat)) -return 0 ; +return false;if (xdr_stream_encode_u32 (xdr, resp->access) <0 ) -return 0 ; +return false;break ; } -return 1 ; +return true; }/*
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 489/770 nfsd: Fix a write performance regression
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Trond Myklebust <[email protected]>
[ Upstream commit 6b8a94332ee4f7d9a8ae0cbac7609f79c212f06c ]
The call to filemap_flush() in nfsd_file_put() is there to ensure that we clear out any writes belonging to a NFSv3 client relatively quickly and avoid situations where the file can't be evicted by the garbage collector. It also ensures that we detect write errors quickly.
The problem is this causes a regression in performance for some workloads.
So try to improve matters by deferring writeback until we're ready to close the file, and need to detect errors so that we can force the client to resend.
--- fs/nfsd/filecache.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
fs/nfsd/filecache.c +15 -3
@@ -235,6 +235,13 @@ nfsd_file_check_write_error(struct nfsd_file *nf)return filemap_check_wb_err (file->f_mapping,READ_ONCE (file->f_wb_err)); } +static void +nfsd_file_flush (struct nfsd_file *nf) +{ +if (nf->nf_file &&vfs_fsync (nf->nf_file,1 ) !=0 ) +nfsd_reset_write_verifier (net_generic (nf->nf_net, nfsd_net_id)); +} +static void nfsd_file_do_unhash (struct nfsd_file *nf) {
@@ -302,11 +309,14 @@ nfsd_file_put(struct nfsd_file *nf)return ; } -filemap_flush (nf->nf_file->f_mapping); is_hashed =test_bit (NFSD_FILE_HASHED , &nf->nf_flags) !=0 ; -nfsd_file_put_noref (nf); -if (is_hashed) +if (!is_hashed) { +nfsd_file_flush (nf); +nfsd_file_put_noref (nf); + }else { +nfsd_file_put_noref (nf);nfsd_file_schedule_laundrette (); + }if (atomic_long_read (&nfsd_filecache_count) >=NFSD_FILE_LRU_LIMIT )nfsd_file_gc (); }
@@ -327,6 +337,7 @@ nfsd_file_dispose_list(struct list_head *dispose)while (!list_empty (dispose)) { nf = list_first_entry(dispose, struct nfsd_file, nf_lru);list_del (&nf->nf_lru); +nfsd_file_flush (nf);nfsd_file_put_noref (nf); } }
@@ -340,6 +351,7 @@ nfsd_file_dispose_list_sync(struct list_head *dispose)while (!list_empty (dispose)) { nf = list_first_entry(dispose, struct nfsd_file, nf_lru);list_del (&nf->nf_lru); +nfsd_file_flush (nf);if (!refcount_dec_and_test (&nf->nf_ref))continue ;if (nfsd_file_free (nf))
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 490/770 nfsd: Clean up nfsd_file_put()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Trond Myklebust <[email protected]>
[ Upstream commit 999397926ab3f78c7d1235cc4ca6e3c89d2769bf ]
Make it a little less racy, by removing the refcount_read() test. Then remove the redundant 'is_hashed' variable.
--- fs/nfsd/filecache.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-)
fs/nfsd/filecache.c +3 -10
@@ -301,21 +301,14 @@ nfsd_file_put_noref(struct nfsd_file *nf)void nfsd_file_put (struct nfsd_file *nf) { -bool is_hashed; -set_bit (NFSD_FILE_REFERENCED , &nf->nf_flags); -if (refcount_read (&nf->nf_ref) >2 || !nf->nf_file) { -nfsd_file_put_noref (nf); -return ; - } - - is_hashed =test_bit (NFSD_FILE_HASHED , &nf->nf_flags) !=0 ; -if (!is_hashed) { +if (test_bit (NFSD_FILE_HASHED , &nf->nf_flags) ==0 ) {nfsd_file_flush (nf);nfsd_file_put_noref (nf); }else {nfsd_file_put_noref (nf); -nfsd_file_schedule_laundrette (); +if (nf->nf_file) +nfsd_file_schedule_laundrette (); }if (atomic_long_read (&nfsd_filecache_count) >=NFSD_FILE_LRU_LIMIT )nfsd_file_gc ();
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 491/770 fanotify: do not allow setting dirent events in mask of non-dir
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit ceaf69f8eadcafb323392be88e7a5248c415d423 ]
Dirent events (create/delete/move) are only reported on watched directory inodes, but in fanotify as well as in legacy inotify, it was always allowed to set them on non-dir inode, which does not result in any meaningful outcome.
Until kernel v5.17, dirent events in fanotify also differed from events "on child" (e.g. FAN_OPEN) in the information provided in the event. For example, FAN_OPEN could be set in the mask of a non-dir or the mask of its parent and event would report the fid of the child regardless of the marked object.
By contrast, FAN_DELETE is not reported if the child is marked and the child fid was not reported in the events.
Since kernel v5.17, with fanotify group flag FAN_REPORT_TARGET_FID, the fid of the child is reported with dirent events, like events "on child", which may create confusion for users expecting the same behavior as events "on child" when setting events in the mask on a child.
The desired semantics of setting dirent events in the mask of a child are not clear, so for now, deny this action for a group initialized with flag FAN_REPORT_TARGET_FID and for the new event FAN_RENAME. We may relax this restriction in the future if we decide on the semantics and implement them.
--- fs/notify/fanotify/fanotify_user.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
fs/notify/fanotify/fanotify_user.c +13 -0
@@ -1663,6 +1663,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,else mnt = path.mnt; +/* +* FAN_RENAME is not allowed on non-dir (for now). +* We shouldn't have allowed setting any dirent events in mask of +* non-dir, but because we always allowed it, error only if group +* was initialized with the new flag FAN_REPORT_TARGET_FID. +*/ + ret = -ENOTDIR ; +if (inode && !S_ISDIR (inode->i_mode) && + ((mask &FAN_RENAME ) || + ((mask &FANOTIFY_DIRENT_EVENTS ) && +FAN_GROUP_FLAG (group,FAN_REPORT_TARGET_FID )))) + goto path_put_and_out; +/* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ if (mnt || !S_ISDIR (inode->i_mode)) { mask &= ~FAN_EVENT_ON_CHILD ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 492/770 fs/lock: documentation cleanup. Replace inode->i_lock with flc_lock.
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit 9d6647762b9c6b555bc83d97d7c93be6057a990f ]
Update lock usage of lock_manager_operations' functions to reflect the changes in commit 6109c85037e5 ("locks: add a dedicated spinlock to protect i_flctx lists").
--- Documentation/filesystems/locking.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
Documentation/filesystems/locking.rst +3 -3
@@ -437,13 +437,13 @@ prototypes:: locking rules: ====================== ============= ================= ========= -ops inode->i_lock blocked_lock_lock may block +ops flc_lock blocked_lock_lock may block ====================== ============= ================= ========= -lm_notify: yes yes no +lm_notify: no yes no lm_grant: no no no lm_break: yes no no lm_change yes no no -lm_breaker_owns_lease: no no no +lm_breaker_owns_lease: yes no no ====================== ============= ================= ========= buffer_head
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 493/770 inotify: move control flags from mask to mark flags
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 38035c04f5865c4ef9597d6beed6a7178f90f64a ]
The inotify control flags in the mark mask (e.g. FS_IN_ONE_SHOT) are not relevant to object interest mask, so move them to the mark flags.
This frees up some bits in the object interest mask.
--- fs/notify/fsnotify.c | 4 +-- fs/notify/inotify/inotify.h | 11 ++++++-- fs/notify/inotify/inotify_fsnotify.c | 2 +- fs/notify/inotify/inotify_user.c | 38 ++++++++++++++++++---------- include/linux/fsnotify_backend.h | 16 +++++++----- 5 files changed, 45 insertions(+), 26 deletions(-)
fs/notify/fsnotify.c +2 -2
@@ -253,7 +253,7 @@ static int fsnotify_handle_inode_event(struct fsnotify_group *group,if (WARN_ON_ONCE (!inode && !dir))return 0 ; -if ((inode_mark->mask &FS_EXCL_UNLINK ) && +if ((inode_mark->flags &FSNOTIFY_MARK_FLAG_EXCL_UNLINK ) && path &&d_unlinked (path->dentry))return 0 ;
@@ -581,7 +581,7 @@ static __init int fsnotify_init(void) {int ret; -BUILD_BUG_ON (HWEIGHT32 (ALL_FSNOTIFY_BITS ) !=25 ); +BUILD_BUG_ON (HWEIGHT32 (ALL_FSNOTIFY_BITS ) !=23 ); ret =init_srcu_struct (&fsnotify_mark_srcu);if (ret)
fs/notify/inotify/inotify.h +9 -2
@@ -27,11 +27,18 @@ static inline struct inotify_event_info *INOTIFY_E(struct fsnotify_event *fse)* userspace. There is at least one bit (FS_EVENT_ON_CHILD) which is * used only internally to the kernel. */ -#define INOTIFY_USER_MASK (IN_ALL_EVENTS | IN_ONESHOT | IN_EXCL_UNLINK) +#define INOTIFY_USER_MASK (IN_ALL_EVENTS)static inline __u32 inotify_mark_user_mask (struct fsnotify_mark *fsn_mark) { -return fsn_mark->mask &INOTIFY_USER_MASK ; +__u32 mask = fsn_mark->mask &INOTIFY_USER_MASK ; + +if (fsn_mark->flags &FSNOTIFY_MARK_FLAG_EXCL_UNLINK ) + mask |=IN_EXCL_UNLINK ; +if (fsn_mark->flags &FSNOTIFY_MARK_FLAG_IN_ONESHOT ) + mask |=IN_ONESHOT ; + +return mask; } extern void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
fs/notify/inotify/inotify_fsnotify.c +1 -1
@@ -129,7 +129,7 @@ int inotify_handle_inode_event(struct fsnotify_mark *inode_mark, u32 mask,fsnotify_destroy_event (group, fsn_event); } -if (inode_mark->mask &IN_ONESHOT ) +if (inode_mark->flags &FSNOTIFY_MARK_FLAG_IN_ONESHOT )fsnotify_destroy_mark (inode_mark, group);return 0 ;
fs/notify/inotify/inotify_user.c +24 -14
@@ -102,6 +102,21 @@ static inline __u32 inotify_arg_to_mask(struct inode *inode, u32 arg)return mask; } +#define INOTIFY_MARK_FLAGS \ + (FSNOTIFY_MARK_FLAG_EXCL_UNLINK | FSNOTIFY_MARK_FLAG_IN_ONESHOT) + +static inline unsigned int inotify_arg_to_flags (u32 arg) +{ +unsigned int flags =0 ; + +if (arg &IN_EXCL_UNLINK ) + flags |=FSNOTIFY_MARK_FLAG_EXCL_UNLINK ; +if (arg &IN_ONESHOT ) + flags |=FSNOTIFY_MARK_FLAG_IN_ONESHOT ; + +return flags; +} +static inline u32 inotify_mask_to_arg (__u32 mask) { return mask & (IN_ALL_EVENTS | IN_ISDIR | IN_UNMOUNT | IN_IGNORED |
@@ -513,13 +528,10 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,struct fsnotify_mark *fsn_mark;struct inotify_inode_mark *i_mark;__u32 old_mask, new_mask; -__u32 mask; -int add = (arg &IN_MASK_ADD ); +int replace = !(arg &IN_MASK_ADD );int create = (arg &IN_MASK_CREATE );int ret; - mask =inotify_arg_to_mask (inode, arg); - fsn_mark =fsnotify_find_mark (&inode->i_fsnotify_marks, group);if (!fsn_mark)return -ENOENT ;
@@ -532,10 +544,12 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,spin_lock (&fsn_mark->lock); old_mask = fsn_mark->mask; -if (add) - fsn_mark->mask |= mask; -else - fsn_mark->mask = mask; +if (replace) { + fsn_mark->mask =0 ; + fsn_mark->flags &= ~INOTIFY_MARK_FLAGS ; + } + fsn_mark->mask |=inotify_arg_to_mask (inode, arg); + fsn_mark->flags |=inotify_arg_to_flags (arg); new_mask = fsn_mark->mask;spin_unlock (&fsn_mark->lock);
@@ -566,19 +580,17 @@ static int inotify_new_watch(struct fsnotify_group *group, u32 arg) {struct inotify_inode_mark *tmp_i_mark; -__u32 mask;int ret;struct idr *idr = &group->inotify_data.idr;spinlock_t *idr_lock = &group->inotify_data.idr_lock; - mask =inotify_arg_to_mask (inode, arg); - tmp_i_mark =kmem_cache_alloc (inotify_inode_mark_cachep,GFP_KERNEL );if (unlikely (!tmp_i_mark))return -ENOMEM ;fsnotify_init_mark (&tmp_i_mark->fsn_mark, group); - tmp_i_mark->fsn_mark.mask = mask; + tmp_i_mark->fsn_mark.mask =inotify_arg_to_mask (inode, arg); + tmp_i_mark->fsn_mark.flags =inotify_arg_to_flags (arg); tmp_i_mark->wd =-1 ; ret =inotify_add_to_idr (idr, idr_lock, tmp_i_mark);
@@ -832,9 +844,7 @@ static int __init inotify_user_setup(void)BUILD_BUG_ON (IN_UNMOUNT !=FS_UNMOUNT );BUILD_BUG_ON (IN_Q_OVERFLOW !=FS_Q_OVERFLOW );BUILD_BUG_ON (IN_IGNORED !=FS_IN_IGNORED ); -BUILD_BUG_ON (IN_EXCL_UNLINK !=FS_EXCL_UNLINK );BUILD_BUG_ON (IN_ISDIR !=FS_ISDIR ); -BUILD_BUG_ON (IN_ONESHOT !=FS_IN_ONESHOT );BUILD_BUG_ON (HWEIGHT32 (ALL_INOTIFY_BITS ) !=22 );
include/linux/fsnotify_backend.h +9 -7
@@ -55,7 +55,6 @@#define FS_ACCESS_PERM 0x00020000/* access event in a permissions hook */ #define FS_OPEN_EXEC_PERM 0x00040000/* open/exec event in a permission hook */ -#define FS_EXCL_UNLINK 0x04000000/* do not send events if object is unlinked */ /* * Set on inode mark that cares about things that happen to its children. * Always set for dnotify and inotify.
@@ -66,7 +65,6 @@#define FS_RENAME 0x10000000/* File was renamed */ #define FS_DN_MULTISHOT 0x20000000/* dnotify multishot */ #define FS_ISDIR 0x40000000/* event occurred against dir */ -#define FS_IN_ONESHOT 0x80000000/* only send event once */ #define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO)
@@ -106,8 +104,7 @@ FS_ERROR)/* Extra flags that may be reported with event or control handling of events */ -#define ALL_FSNOTIFY_FLAGS (FS_EXCL_UNLINK | FS_ISDIR | FS_IN_ONESHOT | \ - FS_DN_MULTISHOT | FS_EVENT_ON_CHILD) +#define ALL_FSNOTIFY_FLAGS (FS_ISDIR | FS_EVENT_ON_CHILD | FS_DN_MULTISHOT)#define ALL_FSNOTIFY_BITS (ALL_FSNOTIFY_EVENTS | ALL_FSNOTIFY_FLAGS)
@@ -473,9 +470,14 @@ struct fsnotify_mark {struct fsnotify_mark_connector *connector;/* Events types to ignore [mark->lock, group->mark_mutex] */ __u32 ignored_mask; -#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x01 -#define FSNOTIFY_MARK_FLAG_ALIVE 0x02 -#define FSNOTIFY_MARK_FLAG_ATTACHED 0x04 +/* General fsnotify mark flags */ +#define FSNOTIFY_MARK_FLAG_ALIVE 0x0001 +#define FSNOTIFY_MARK_FLAG_ATTACHED 0x0002 +/* inotify mark flags */ +#define FSNOTIFY_MARK_FLAG_EXCL_UNLINK 0x0010 +#define FSNOTIFY_MARK_FLAG_IN_ONESHOT 0x0020 +/* fanotify mark flags */ +#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100unsigned int flags;/* flags [mark->lock] */ };
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 494/770 fsnotify: pass flags argument to fsnotify_alloc_group()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 867a448d587e7fa845bceaf4ee1c632448f2a9fa ]
Add flags argument to fsnotify_alloc_group(), define and use the flag FSNOTIFY_GROUP_USER in inotify and fanotify instead of the helper fsnotify_alloc_user_group() to indicate user allocation.
Although the flag FSNOTIFY_GROUP_USER is currently not used after group allocation, we store the flags argument in the group struct for future use of other group flags.
--- fs/nfsd/filecache.c | 3 ++- fs/notify/dnotify/dnotify.c | 2 +- fs/notify/fanotify/fanotify_user.c | 3 ++- fs/notify/group.c | 21 +++++++++------------ fs/notify/inotify/inotify_user.c | 3 ++- include/linux/fsnotify_backend.h | 8 ++++++-- kernel/audit_fsnotify.c | 3 ++- kernel/audit_tree.c | 2 +- kernel/audit_watch.c | 2 +- 9 files changed, 26 insertions(+), 21 deletions(-)
fs/nfsd/filecache.c +2 -1
@@ -677,7 +677,8 @@ nfsd_file_cache_init(void) goto out_shrinker; } - nfsd_file_fsnotify_group =fsnotify_alloc_group (&nfsd_file_fsnotify_ops); + nfsd_file_fsnotify_group =fsnotify_alloc_group (&nfsd_file_fsnotify_ops, +0 );if (IS_ERR (nfsd_file_fsnotify_group)) {pr_err ("nfsd: unable to create fsnotify group: %ld\n" ,PTR_ERR (nfsd_file_fsnotify_group));
fs/notify/dnotify/dnotify.c +1 -1
@@ -383,7 +383,7 @@ static int __init dnotify_init(void) SLAB_PANIC|SLAB_ACCOUNT); dnotify_mark_cache =KMEM_CACHE (dnotify_mark,SLAB_PANIC |SLAB_ACCOUNT ); - dnotify_group =fsnotify_alloc_group (&dnotify_fsnotify_ops); + dnotify_group =fsnotify_alloc_group (&dnotify_fsnotify_ops,0 );if (IS_ERR (dnotify_group))panic ("unable to allocate fsnotify group for dnotify\n" );return 0 ;
fs/notify/fanotify/fanotify_user.c +2 -1
@@ -1343,7 +1343,8 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) f_flags |=O_NONBLOCK ;/* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ - group =fsnotify_alloc_user_group (&fanotify_fsnotify_ops); + group =fsnotify_alloc_group (&fanotify_fsnotify_ops, +FSNOTIFY_GROUP_USER );if (IS_ERR (group)) {return PTR_ERR (group); }
fs/notify/group.c +9 -12
@@ -112,7 +112,8 @@ void fsnotify_put_group(struct fsnotify_group *group)EXPORT_SYMBOL_GPL (fsnotify_put_group);static struct fsnotify_group *__fsnotify_alloc_group ( -const struct fsnotify_ops *ops,gfp_t gfp) +const struct fsnotify_ops *ops, +int flags,gfp_t gfp) {struct fsnotify_group *group;
@@ -133,6 +134,7 @@ static struct fsnotify_group *__fsnotify_alloc_group(INIT_LIST_HEAD (&group->marks_list); group->ops = ops; + group->flags = flags;return group; }
@@ -140,20 +142,15 @@ static struct fsnotify_group *__fsnotify_alloc_group(/* * Create a new fsnotify_group and hold a reference for the group returned. */ -struct fsnotify_group *fsnotify_alloc_group (const struct fsnotify_ops *ops) +struct fsnotify_group *fsnotify_alloc_group (const struct fsnotify_ops *ops, +int flags) { -return __fsnotify_alloc_group (ops,GFP_KERNEL ); -} -EXPORT_SYMBOL_GPL (fsnotify_alloc_group); +gfp_t gfp = (flags &FSNOTIFY_GROUP_USER ) ?GFP_KERNEL_ACCOUNT : +GFP_KERNEL ; -/* -* Create a new fsnotify_group and hold a reference for the group returned. -*/ -struct fsnotify_group *fsnotify_alloc_user_group (const struct fsnotify_ops *ops) -{ -return __fsnotify_alloc_group (ops,GFP_KERNEL_ACCOUNT ); +return __fsnotify_alloc_group (ops, flags, gfp); } -EXPORT_SYMBOL_GPL (fsnotify_alloc_user_group); +EXPORT_SYMBOL_GPL (fsnotify_alloc_group);int fsnotify_fasync (int fd,struct file *file,int on) {
fs/notify/inotify/inotify_user.c +2 -1
@@ -643,7 +643,8 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)struct fsnotify_group *group;struct inotify_event_info *oevent; - group =fsnotify_alloc_user_group (&inotify_fsnotify_ops); + group =fsnotify_alloc_group (&inotify_fsnotify_ops, +FSNOTIFY_GROUP_USER );if (IS_ERR (group))return group;
include/linux/fsnotify_backend.h +6 -2
@@ -210,6 +210,9 @@ struct fsnotify_group {unsigned int priority;bool shutdown;/* group is being shut down, don't queue more events */ +#define FSNOTIFY_GROUP_USER 0x01/* user allocated group */ +int flags; +/* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ struct mutex mark_mutex;/* protect marks_list */ atomic_t user_waits;/* Number of tasks waiting for user
@@ -543,8 +546,9 @@ static inline void fsnotify_update_flags(struct dentry *dentry)/* called from fsnotify listeners, such as fanotify or dnotify */ /* create a new group */ -extern struct fsnotify_group *fsnotify_alloc_group (const struct fsnotify_ops *ops); -extern struct fsnotify_group *fsnotify_alloc_user_group (const struct fsnotify_ops *ops); +extern struct fsnotify_group *fsnotify_alloc_group ( +const struct fsnotify_ops *ops, +int flags);/* get reference to a group */ extern void fsnotify_get_group (struct fsnotify_group *group);/* drop reference on a group from fsnotify_alloc_group */
kernel/audit_fsnotify.c +2 -1
@@ -182,7 +182,8 @@ static const struct fsnotify_ops audit_mark_fsnotify_ops = {static int __init audit_fsnotify_init (void ) { - audit_fsnotify_group =fsnotify_alloc_group (&audit_mark_fsnotify_ops); + audit_fsnotify_group =fsnotify_alloc_group (&audit_mark_fsnotify_ops, +0 );if (IS_ERR (audit_fsnotify_group)) { audit_fsnotify_group =NULL ;audit_panic ("cannot create audit fsnotify group" );
kernel/audit_tree.c +1 -1
@@ -1077,7 +1077,7 @@ static int __init audit_tree_init(void) audit_tree_mark_cachep =KMEM_CACHE (audit_tree_mark,SLAB_PANIC ); - audit_tree_group =fsnotify_alloc_group (&audit_tree_ops); + audit_tree_group =fsnotify_alloc_group (&audit_tree_ops,0 );if (IS_ERR (audit_tree_group))audit_panic ("cannot initialize fsnotify group for rectree watches" );
kernel/audit_watch.c +1 -1
@@ -492,7 +492,7 @@ static const struct fsnotify_ops audit_watch_fsnotify_ops = {static int __init audit_watch_init (void ) { - audit_watch_group =fsnotify_alloc_group (&audit_watch_fsnotify_ops); + audit_watch_group =fsnotify_alloc_group (&audit_watch_fsnotify_ops,0 );if (IS_ERR (audit_watch_group)) { audit_watch_group =NULL ;audit_panic ("cannot create audit fsnotify group" );
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 495/770 fsnotify: make allow_dups a property of the group
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit f3010343d9e119da35ee864b3a28993bb5c78ed7 ]
Instead of passing the allow_dups argument to fsnotify_add_mark() as an argument, define the group flag FSNOTIFY_GROUP_DUPS to express the allow_dups behavior and set this behavior at group creation time for all calls of fsnotify_add_mark().
Rename the allow_dups argument to generic add_flags argument for future use.
--- fs/notify/mark.c | 12 ++++++------ include/linux/fsnotify_backend.h | 13 +++++++------ kernel/audit_fsnotify.c | 4 ++-- 3 files changed, 15 insertions(+), 14 deletions(-)
fs/notify/mark.c +6 -6
@@ -574,7 +574,7 @@ static struct fsnotify_mark_connector *fsnotify_grab_connector(static int fsnotify_add_mark_list (struct fsnotify_mark *mark,fsnotify_connp_t *connp,unsigned int obj_type, -int allow_dups,__kernel_fsid_t *fsid) +int add_flags,__kernel_fsid_t *fsid) {struct fsnotify_mark *lmark, *last =NULL ;struct fsnotify_mark_connector *conn;
@@ -633,7 +633,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark,if ((lmark->group == mark->group) && (lmark->flags &FSNOTIFY_MARK_FLAG_ATTACHED ) && - !allow_dups) { + !(mark->group->flags &FSNOTIFY_GROUP_DUPS )) { err = -EEXIST ; goto out_err; }
@@ -668,7 +668,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark,*/ int fsnotify_add_mark_locked (struct fsnotify_mark *mark,fsnotify_connp_t *connp,unsigned int obj_type, -int allow_dups,__kernel_fsid_t *fsid) +int add_flags,__kernel_fsid_t *fsid) {struct fsnotify_group *group = mark->group;int ret =0 ;
@@ -688,7 +688,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,fsnotify_get_mark (mark);/* for g_list */ spin_unlock (&mark->lock); - ret =fsnotify_add_mark_list (mark, connp, obj_type, allow_dups, fsid); + ret =fsnotify_add_mark_list (mark, connp, obj_type, add_flags, fsid);if (ret) goto err;
@@ -708,14 +708,14 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, }int fsnotify_add_mark (struct fsnotify_mark *mark,fsnotify_connp_t *connp, -unsigned int obj_type,int allow_dups, +unsigned int obj_type,int add_flags,__kernel_fsid_t *fsid) {int ret;struct fsnotify_group *group = mark->group;mutex_lock (&group->mark_mutex); - ret =fsnotify_add_mark_locked (mark, connp, obj_type, allow_dups, fsid); + ret =fsnotify_add_mark_locked (mark, connp, obj_type, add_flags, fsid);mutex_unlock (&group->mark_mutex);return ret; }
include/linux/fsnotify_backend.h +7 -6
@@ -211,6 +211,7 @@ struct fsnotify_group {bool shutdown;/* group is being shut down, don't queue more events */ #define FSNOTIFY_GROUP_USER 0x01/* user allocated group */ +#define FSNOTIFY_GROUP_DUPS 0x02/* allow multiple marks per object */ int flags;/* stores all fastpath marks assoc with this group so they can be cleaned on unregister */
@@ -641,26 +642,26 @@ extern int fsnotify_get_conn_fsid(const struct fsnotify_mark_connector *conn,/* attach the mark to the object */ extern int fsnotify_add_mark (struct fsnotify_mark *mark,fsnotify_connp_t *connp,unsigned int obj_type, -int allow_dups,__kernel_fsid_t *fsid); +int add_flags,__kernel_fsid_t *fsid);extern int fsnotify_add_mark_locked (struct fsnotify_mark *mark,fsnotify_connp_t *connp, -unsigned int obj_type,int allow_dups, +unsigned int obj_type,int add_flags,__kernel_fsid_t *fsid);/* attach the mark to the inode */ static inline int fsnotify_add_inode_mark (struct fsnotify_mark *mark,struct inode *inode, -int allow_dups) +int add_flags) {return fsnotify_add_mark (mark, &inode->i_fsnotify_marks, -FSNOTIFY_OBJ_TYPE_INODE , allow_dups,NULL ); +FSNOTIFY_OBJ_TYPE_INODE , add_flags,NULL ); }static inline int fsnotify_add_inode_mark_locked (struct fsnotify_mark *mark,struct inode *inode, -int allow_dups) +int add_flags) {return fsnotify_add_mark_locked (mark, &inode->i_fsnotify_marks, -FSNOTIFY_OBJ_TYPE_INODE , allow_dups, +FSNOTIFY_OBJ_TYPE_INODE , add_flags,NULL ); }
kernel/audit_fsnotify.c +2 -2
@@ -100,7 +100,7 @@ struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *paaudit_update_mark (audit_mark, dentry->d_inode); audit_mark->rule = krule; - ret =fsnotify_add_inode_mark (&audit_mark->mark, inode, true); + ret =fsnotify_add_inode_mark (&audit_mark->mark, inode,0 );if (ret <0 ) { audit_mark->path =NULL ;fsnotify_put_mark (&audit_mark->mark);
@@ -183,7 +183,7 @@ static const struct fsnotify_ops audit_mark_fsnotify_ops = {static int __init audit_fsnotify_init (void ) { audit_fsnotify_group =fsnotify_alloc_group (&audit_mark_fsnotify_ops, -0 ); +FSNOTIFY_GROUP_DUPS );if (IS_ERR (audit_fsnotify_group)) { audit_fsnotify_group =NULL ;audit_panic ("cannot create audit fsnotify group" );
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 496/770 fsnotify: create helpers for group mark_mutex lock
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 43b245a788e2d8f1bb742668a9bdace02fcb3e96 ]
Create helpers to take and release the group mark_mutex lock.
Define a flag FSNOTIFY_GROUP_NOFS in fsnotify_group that determines if the mark_mutex lock is fs reclaim safe or not. If not safe, the lock helpers take the lock and disable direct fs reclaim.
In that case we annotate the mutex with a different lockdep class to express to lockdep that an allocation of mark of an fs reclaim safe group may take the group lock of another "NOFS" group to evict inodes.
For now, converted only the callers in common code and no backend defines the NOFS flag. It is intended to be set by fanotify for evictable marks support.
--- fs/notify/fdinfo.c | 4 ++-- fs/notify/group.c | 11 +++++++++++ fs/notify/mark.c | 24 +++++++++++------------- include/linux/fsnotify_backend.h | 28 ++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 15 deletions(-)
fs/notify/fdinfo.c +2 -2
@@ -28,13 +28,13 @@ static void show_fdinfo(struct seq_file *m, struct file *f,struct fsnotify_group *group = f->private_data;struct fsnotify_mark *mark; -mutex_lock (&group->mark_mutex); +fsnotify_group_lock (group);list_for_each_entry (mark, &group->marks_list, g_list) {show (m, mark);if (seq_has_overflowed (m))break ; } -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group); }#if defined(CONFIG_EXPORTFS )
fs/notify/group.c +11 -0
@@ -115,6 +115,7 @@ static struct fsnotify_group *__fsnotify_alloc_group(const struct fsnotify_ops *ops, int flags, gfp_t gfp) { + static struct lock_class_key nofs_marks_lock;struct fsnotify_group *group; group =kzalloc (sizeof (struct fsnotify_group ), gfp);
@@ -135,6 +136,16 @@ static struct fsnotify_group *__fsnotify_alloc_group( group->ops = ops; group->flags = flags; +/* +* For most backends, eviction of inode with a mark is not expected, +* because marks hold a refcount on the inode against eviction. +* +* Use a different lockdep class for groups that support evictable +* inode marks, because with evictable marks, mark_mutex is NOT +* fs-reclaim safe - the mutex is taken when evicting inodes. +*/ +if (flags &FSNOTIFY_GROUP_NOFS ) +lockdep_set_class (&group->mark_mutex, &nofs_marks_lock);return group; }
fs/notify/mark.c +11 -13
@@ -398,9 +398,7 @@ void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info)*/ void fsnotify_detach_mark (struct fsnotify_mark *mark) { -struct fsnotify_group *group = mark->group; - -WARN_ON_ONCE (!mutex_is_locked (&group->mark_mutex)); +fsnotify_group_assert_locked (mark->group);WARN_ON_ONCE (!srcu_read_lock_held (&fsnotify_mark_srcu) &&refcount_read (&mark->refcnt) <1 + !!(mark->flags &FSNOTIFY_MARK_FLAG_ATTACHED ));
@@ -452,9 +450,9 @@ void fsnotify_free_mark(struct fsnotify_mark *mark)void fsnotify_destroy_mark (struct fsnotify_mark *mark,struct fsnotify_group *group) { -mutex_lock (&group->mark_mutex); +fsnotify_group_lock (group);fsnotify_detach_mark (mark); -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group);fsnotify_free_mark (mark); }EXPORT_SYMBOL_GPL (fsnotify_destroy_mark);
@@ -673,7 +671,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,struct fsnotify_group *group = mark->group;int ret =0 ; -BUG_ON (!mutex_is_locked (&group->mark_mutex)); +fsnotify_group_assert_locked (group);/* * LOCKING ORDER!!!!
@@ -714,9 +712,9 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp,int ret;struct fsnotify_group *group = mark->group; -mutex_lock (&group->mark_mutex); +fsnotify_group_lock (group); ret =fsnotify_add_mark_locked (mark, connp, obj_type, add_flags, fsid); -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group);return ret; }EXPORT_SYMBOL_GPL (fsnotify_add_mark);
@@ -770,24 +768,24 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group,* move marks to free to to_free list in one go and then free marks in * to_free list one by one. */ -mutex_lock (&group->mark_mutex); +fsnotify_group_lock (group);list_for_each_entry_safe (mark, lmark, &group->marks_list, g_list) {if (mark->connector->type == obj_type)list_move (&mark->g_list, &to_free); } -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group); clear:while (1 ) { -mutex_lock (&group->mark_mutex); +fsnotify_group_lock (group);if (list_empty (head)) { -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group);break ; } mark = list_first_entry(head, struct fsnotify_mark, g_list);fsnotify_get_mark (mark);fsnotify_detach_mark (mark); -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group);fsnotify_free_mark (mark);fsnotify_put_mark (mark); }
include/linux/fsnotify_backend.h +28 -0
@@ -20,6 +20,7 @@#include <linux/user_namespace.h> #include <linux/refcount.h> #include <linux/mempool.h> +#include <linux/sched/mm.h> /* * IN_* from inotfy.h lines up EXACTLY with FS_*, this is so we can easily
@@ -212,7 +213,9 @@ struct fsnotify_group {#define FSNOTIFY_GROUP_USER 0x01/* user allocated group */ #define FSNOTIFY_GROUP_DUPS 0x02/* allow multiple marks per object */ +#define FSNOTIFY_GROUP_NOFS 0x04/* group lock is not direct reclaim safe */ int flags; +unsigned int owner_flags;/* stored flags of mark_mutex owner */ /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ struct mutex mark_mutex;/* protect marks_list */
@@ -254,6 +257,31 @@ struct fsnotify_group { }; }; +/* +* These helpers are used to prevent deadlock when reclaiming inodes with +* evictable marks of the same group that is allocating a new mark. +*/ +static inline void fsnotify_group_lock (struct fsnotify_group *group) +{ +mutex_lock (&group->mark_mutex); +if (group->flags &FSNOTIFY_GROUP_NOFS ) + group->owner_flags =memalloc_nofs_save (); +} + +static inline void fsnotify_group_unlock (struct fsnotify_group *group) +{ +if (group->flags &FSNOTIFY_GROUP_NOFS ) +memalloc_nofs_restore (group->owner_flags); +mutex_unlock (&group->mark_mutex); +} + +static inline void fsnotify_group_assert_locked (struct fsnotify_group *group) +{ +WARN_ON_ONCE (!mutex_is_locked (&group->mark_mutex)); +if (group->flags &FSNOTIFY_GROUP_NOFS ) +WARN_ON_ONCE (!(current->flags &PF_MEMALLOC_NOFS )); +} +/* When calling fsnotify tell it if the data is a path or inode */ enum fsnotify_data_type {FSNOTIFY_EVENT_NONE ,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 497/770 inotify: use fsnotify group lock helpers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 642054b87058019be36033f73c3e48ffff1915aa ]
inotify inode marks pin the inode so there is no need to set the FSNOTIFY_GROUP_NOFS flag.
--- fs/notify/inotify/inotify_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/notify/inotify/inotify_user.c +2 -2
@@ -627,13 +627,13 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod {int ret =0 ; -mutex_lock (&group->mark_mutex); +fsnotify_group_lock (group);/* try to update and existing watch with the new arg */ ret =inotify_update_existing_watch (group, inode, arg);/* no mark present, try to add a new one */ if (ret == -ENOENT ) ret =inotify_new_watch (group, inode, arg); -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group);return ret; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 498/770 nfsd: use fsnotify group lock helpers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit b8962a9d8cc2d8c93362e2f684091c79f702f6f3 ]
Before commit 9542e6a643fc6 ("nfsd: Containerise filecache laundrette") nfsd would close open files in direct reclaim context and that could cause a deadlock when fsnotify mark allocation went into direct reclaim and nfsd shrinker tried to free existing fsnotify marks.
To avoid issues like this in future code, set the FSNOTIFY_GROUP_NOFS flag on nfsd fsnotify group to prevent going into direct reclaim from fsnotify_add_inode_mark().
--- fs/nfsd/filecache.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
fs/nfsd/filecache.c +7 -6
@@ -118,14 +118,14 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf)struct inode *inode = nf->nf_inode; do { - mutex_lock(&nfsd_file_fsnotify_group->mark_mutex); + fsnotify_group_lock(nfsd_file_fsnotify_group); mark = fsnotify_find_mark(&inode->i_fsnotify_marks, - nfsd_file_fsnotify_group); + nfsd_file_fsnotify_group); if (mark) { nfm = nfsd_file_mark_get(container_of(mark, struct nfsd_file_mark, nfm_mark)); - mutex_unlock(&nfsd_file_fsnotify_group->mark_mutex); + fsnotify_group_unlock(nfsd_file_fsnotify_group); if (nfm) { fsnotify_put_mark(mark); break;
@@ -133,8 +133,9 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf)/* Avoid soft lockup race with nfsd_file_mark_put() */ fsnotify_destroy_mark (mark, nfsd_file_fsnotify_group);fsnotify_put_mark (mark); - }else -mutex_unlock (&nfsd_file_fsnotify_group->mark_mutex); + }else { +fsnotify_group_unlock (nfsd_file_fsnotify_group); + }/* allocate a new nfm */ new =kmem_cache_alloc (nfsd_file_mark_slab,GFP_KERNEL );
@@ -678,7 +679,7 @@ nfsd_file_cache_init(void) } nfsd_file_fsnotify_group =fsnotify_alloc_group (&nfsd_file_fsnotify_ops, -0 ); +FSNOTIFY_GROUP_NOFS );if (IS_ERR (nfsd_file_fsnotify_group)) {pr_err ("nfsd: unable to create fsnotify group: %ld\n" ,PTR_ERR (nfsd_file_fsnotify_group));
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 499/770 dnotify: use fsnotify group lock helpers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit aabb45fdcb31f00f1e7cae2bce83e83474a87c03 ]
Before commit 9542e6a643fc6 ("nfsd: Containerise filecache laundrette") nfsd would close open files in direct reclaim context. There is no guarantee that others memory shrinkers don't do the same and no guarantee that future shrinkers won't do that.
For example, if overlayfs implements inode cache of fscache would keep open files to cached objects, inode shrinkers could end up closing open files to underlying fs.
Direct reclaim from dnotify mark allocation context may try to close open files that have dnotify marks of the same group and hit a deadlock on mark_mutex.
Set the FSNOTIFY_GROUP_NOFS flag to prevent going into direct reclaim from allocations under dnotify group lock and use the safe group lock helpers.
--- fs/notify/dnotify/dnotify.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
fs/notify/dnotify/dnotify.c +7 -6
@@ -150,7 +150,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id)return ; dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); -mutex_lock (&dnotify_group->mark_mutex); +fsnotify_group_lock (dnotify_group);spin_lock (&fsn_mark->lock); prev = &dn_mark->dn;
@@ -173,7 +173,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id) free = true; } -mutex_unlock (&dnotify_group->mark_mutex); +fsnotify_group_unlock (dnotify_group);if (free)fsnotify_free_mark (fsn_mark);
@@ -306,7 +306,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) new_dn_mark->dn =NULL ;/* this is needed to prevent the fcntl/close race described below */ -mutex_lock (&dnotify_group->mark_mutex); +fsnotify_group_lock (dnotify_group);/* add the new_fsn_mark or find an old one. */ fsn_mark =fsnotify_find_mark (&inode->i_fsnotify_marks, dnotify_group);
@@ -316,7 +316,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) }else { error =fsnotify_add_inode_mark_locked (new_fsn_mark, inode,0 );if (error) { -mutex_unlock (&dnotify_group->mark_mutex); +fsnotify_group_unlock (dnotify_group); goto out_err; }spin_lock (&new_fsn_mark->lock);
@@ -365,7 +365,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)if (destroy)fsnotify_detach_mark (fsn_mark); -mutex_unlock (&dnotify_group->mark_mutex); +fsnotify_group_unlock (dnotify_group);if (destroy)fsnotify_free_mark (fsn_mark);fsnotify_put_mark (fsn_mark);
@@ -383,7 +383,8 @@ static int __init dnotify_init(void) SLAB_PANIC|SLAB_ACCOUNT); dnotify_mark_cache =KMEM_CACHE (dnotify_mark,SLAB_PANIC |SLAB_ACCOUNT ); - dnotify_group =fsnotify_alloc_group (&dnotify_fsnotify_ops,0 ); + dnotify_group =fsnotify_alloc_group (&dnotify_fsnotify_ops, +FSNOTIFY_GROUP_NOFS );if (IS_ERR (dnotify_group))panic ("unable to allocate fsnotify group for dnotify\n" );return 0 ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 500/770 fsnotify: allow adding an inode mark without pinning inode
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit c3638b5b13740fa31762d414bbce8b7a694e582a ]
fsnotify_add_mark() and variants implicitly take a reference on inode when attaching a mark to an inode.
Make that behavior opt-out with the mark flag FSNOTIFY_MARK_FLAG_NO_IREF.
Instead of taking the inode reference when attaching connector to inode and dropping the inode reference when detaching connector from inode, take the inode reference on attach of the first mark that wants to hold an inode reference and drop the inode reference on detach of the last mark that wants to hold an inode reference.
Backends can "upgrade" an existing mark to take an inode reference, but cannot "downgrade" a mark with inode reference to release the refernce.
This leaves the choice to the backend whether or not to pin the inode when adding an inode mark.
This is intended to be used when adding a mark with ignored mask that is used for optimization in cases where group can afford getting unneeded events and reinstate the mark with ignored mask when inode is accessed again after being evicted.
--- fs/notify/mark.c | 76 +++++++++++++++++++++++--------- include/linux/fsnotify_backend.h | 2 + 2 files changed, 58 insertions(+), 20 deletions(-)
fs/notify/mark.c +56 -20
@@ -116,20 +116,64 @@ __u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn)return *fsnotify_conn_mask_p (conn); } -static void __fsnotify_recalc_mask (struct fsnotify_mark_connector *conn) +static void fsnotify_get_inode_ref (struct inode *inode) +{ +ihold (inode); +atomic_long_inc (&inode->i_sb->s_fsnotify_connectors); +} + +/* +* Grab or drop inode reference for the connector if needed. +* +* When it's time to drop the reference, we only clear the HAS_IREF flag and +* return the inode object. fsnotify_drop_object() will be resonsible for doing +* iput() outside of spinlocks. This happens when last mark that wanted iref is +* detached. +*/ +static struct inode *fsnotify_update_iref (struct fsnotify_mark_connector *conn, +bool want_iref) +{ +bool has_iref = conn->flags &FSNOTIFY_CONN_FLAG_HAS_IREF ; +struct inode *inode =NULL ; + +if (conn->type !=FSNOTIFY_OBJ_TYPE_INODE || + want_iref == has_iref) +return NULL ; + +if (want_iref) { +/* Pin inode if any mark wants inode refcount held */ +fsnotify_get_inode_ref (fsnotify_conn_inode (conn)); + conn->flags |=FSNOTIFY_CONN_FLAG_HAS_IREF ; + }else { +/* Unpin inode after detach of last mark that wanted iref */ + inode =fsnotify_conn_inode (conn); + conn->flags &= ~FSNOTIFY_CONN_FLAG_HAS_IREF ; + } + +return inode; +} + +static void *__fsnotify_recalc_mask (struct fsnotify_mark_connector *conn) {u32 new_mask =0 ; +bool want_iref = false;struct fsnotify_mark *mark;assert_spin_locked (&conn->lock);/* We can get detached connector here when inode is getting unlinked. */ if (!fsnotify_valid_obj_type (conn->type)) -return ; +return NULL ;hlist_for_each_entry (mark, &conn->list, obj_list) { -if (mark->flags &FSNOTIFY_MARK_FLAG_ATTACHED ) - new_mask |=fsnotify_calc_mask (mark); +if (!(mark->flags &FSNOTIFY_MARK_FLAG_ATTACHED )) +continue ; + new_mask |=fsnotify_calc_mask (mark); +if (conn->type ==FSNOTIFY_OBJ_TYPE_INODE && + !(mark->flags &FSNOTIFY_MARK_FLAG_NO_IREF )) + want_iref = true; } *fsnotify_conn_mask_p (conn) = new_mask; + +return fsnotify_update_iref (conn, want_iref); }/*
@@ -169,12 +213,6 @@ static void fsnotify_connector_destroy_workfn(struct work_struct *work) } } -static void fsnotify_get_inode_ref (struct inode *inode) -{ -ihold (inode); -atomic_long_inc (&inode->i_sb->s_fsnotify_connectors); -} -static void fsnotify_put_inode_ref (struct inode *inode) {struct super_block *sb = inode->i_sb;
@@ -213,6 +251,10 @@ static void *fsnotify_detach_connector_from_object(if (conn->type ==FSNOTIFY_OBJ_TYPE_INODE ) { inode =fsnotify_conn_inode (conn); inode->i_fsnotify_mask =0 ; + +/* Unpin inode when detaching from connector */ +if (!(conn->flags &FSNOTIFY_CONN_FLAG_HAS_IREF )) + inode =NULL ; }else if (conn->type ==FSNOTIFY_OBJ_TYPE_VFSMOUNT ) {fsnotify_conn_mount (conn)->mnt_fsnotify_mask =0 ; }else if (conn->type ==FSNOTIFY_OBJ_TYPE_SB ) {
@@ -274,7 +316,8 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) objp =fsnotify_detach_connector_from_object (conn, &type); free_conn = true; }else { -__fsnotify_recalc_mask (conn); + objp =__fsnotify_recalc_mask (conn); + type = conn->type; }WRITE_ONCE (mark->connector,NULL );spin_unlock (&conn->lock);
@@ -497,7 +540,6 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,unsigned int obj_type, __kernel_fsid_t *fsid) { - struct inode *inode = NULL; struct fsnotify_mark_connector *conn; conn =kmem_cache_alloc (fsnotify_mark_connector_cachep,GFP_KERNEL );
@@ -505,6 +547,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,return -ENOMEM ;spin_lock_init (&conn->lock);INIT_HLIST_HEAD (&conn->list); + conn->flags =0 ; conn->type = obj_type; conn->obj = connp;/* Cache fsid of filesystem containing the object */
@@ -515,10 +558,6 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, conn->fsid.val[0 ] = conn->fsid.val[1 ] =0 ; conn->flags =0 ; } -if (conn->type ==FSNOTIFY_OBJ_TYPE_INODE ) { - inode =fsnotify_conn_inode (conn); -fsnotify_get_inode_ref (inode); - }fsnotify_get_sb_connectors (conn);/*
@@ -527,8 +566,6 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,*/ if (cmpxchg (connp,NULL , conn)) {/* Someone else created list structure for us */ -if (inode) -fsnotify_put_inode_ref (inode);fsnotify_put_sb_connectors (conn);kmem_cache_free (fsnotify_mark_connector_cachep, conn); }
@@ -690,8 +727,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,if (ret) goto err; -if (mark->mask || mark->ignored_mask) -fsnotify_recalc_mask (mark->connector); +fsnotify_recalc_mask (mark->connector);return ret; err:
include/linux/fsnotify_backend.h +2 -0
@@ -456,6 +456,7 @@ struct fsnotify_mark_connector {spinlock_t lock;unsigned short type;/* Type of object [lock] */ #define FSNOTIFY_CONN_FLAG_HAS_FSID 0x01 +#define FSNOTIFY_CONN_FLAG_HAS_IREF 0x02unsigned short flags;/* flags [lock] */ __kernel_fsid_t fsid;/* fsid of filesystem containing object */ union {
@@ -510,6 +511,7 @@ struct fsnotify_mark {#define FSNOTIFY_MARK_FLAG_IN_ONESHOT 0x0020/* fanotify mark flags */ #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100 +#define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200unsigned int flags;/* flags [mark->lock] */ };
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 501/770 fanotify: create helper fanotify_mark_user_flags()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 4adce25ccfff215939ee465b8c0aa70526d5c352 ]
To translate from fsnotify mark flags to user visible flags.
--- fs/notify/fanotify/fanotify.h | 10 ++++++++++ fs/notify/fdinfo.c | 6 ++---- 2 files changed, 12 insertions(+), 4 deletions(-)
fs/notify/fanotify/fanotify.h +10 -0
@@ -490,3 +490,13 @@ static inline unsigned int fanotify_event_hash_bucket( {return event->hash &FANOTIFY_HTABLE_MASK ; } + +static inline unsigned int fanotify_mark_user_flags (struct fsnotify_mark *mark) +{ +unsigned int mflags =0 ; + +if (mark->flags &FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ) + mflags |=FAN_MARK_IGNORED_SURV_MODIFY ; + +return mflags; +}
fs/notify/fdinfo.c +2 -4
@@ -14,6 +14,7 @@#include <linux/exportfs.h> #include "inotify/inotify.h" +#include "fanotify/fanotify.h" #include "fdinfo.h" #include "fsnotify.h"
@@ -103,12 +104,9 @@ void inotify_show_fdinfo(struct seq_file *m, struct file *f)static void fanotify_fdinfo (struct seq_file *m,struct fsnotify_mark *mark) { -unsigned int mflags =0 ; +unsigned int mflags =fanotify_mark_user_flags (mark);struct inode *inode; -if (mark->flags &FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ) - mflags |=FAN_MARK_IGNORED_SURV_MODIFY ; -if (mark->connector->type ==FSNOTIFY_OBJ_TYPE_INODE ) { inode =igrab (fsnotify_conn_inode (mark->connector));if (!inode)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 502/770 fanotify: factor out helper fanotify_mark_update_flags()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 8998d110835e3781ccd3f1ae061a590b4aaba911 ]
Handle FAN_MARK_IGNORED_SURV_MODIFY flag change in a helper that is called after updating the mark mask.
Replace the added and removed return values and help variables with bool recalc return values and help variable, which makes the code a bit easier to follow.
Rename flags argument to fan_flags to emphasize the difference from mark->flags.
--- fs/notify/fanotify/fanotify_user.c | 47 ++++++++++++++++-------------- 1 file changed, 25 insertions(+), 22 deletions(-)
fs/notify/fanotify/fanotify_user.c +25 -22
@@ -1069,42 +1069,45 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, flags, umask); } -static void fanotify_mark_add_ignored_mask (struct fsnotify_mark *fsn_mark, -__u32 mask,unsigned int flags, -__u32 *removed) +static bool fanotify_mark_update_flags (struct fsnotify_mark *fsn_mark, +unsigned int fan_flags) { - fsn_mark->ignored_mask |= mask; +bool recalc = false;/* * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to * the removal of the FS_MODIFY bit in calculated mask if it was set * because of an ignored mask that is now going to survive FS_MODIFY. */ -if ((flags &FAN_MARK_IGNORED_SURV_MODIFY ) && +if ((fan_flags &FAN_MARK_IGNORED_MASK ) && + (fan_flags &FAN_MARK_IGNORED_SURV_MODIFY ) && !(fsn_mark->flags &FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY )) { fsn_mark->flags |=FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ;if (!(fsn_mark->mask &FS_MODIFY )) - *removed =FS_MODIFY ; + recalc = true; } + +return recalc; } -static __u32 fanotify_mark_add_to_mask (struct fsnotify_mark *fsn_mark, -__u32 mask,unsigned int flags, -__u32 *removed) +static bool fanotify_mark_add_to_mask (struct fsnotify_mark *fsn_mark, +__u32 mask,unsigned int fan_flags) { -__u32 oldmask, newmask; +bool recalc;spin_lock (&fsn_mark->lock); - oldmask =fsnotify_calc_mask (fsn_mark); -if (!(flags &FAN_MARK_IGNORED_MASK )) { +if (!(fan_flags &FAN_MARK_IGNORED_MASK )) fsn_mark->mask |= mask; - }else { -fanotify_mark_add_ignored_mask (fsn_mark, mask, flags, removed); - } - newmask =fsnotify_calc_mask (fsn_mark); +else + fsn_mark->ignored_mask |= mask; + + recalc =fsnotify_calc_mask (fsn_mark) & + ~fsnotify_conn_mask (fsn_mark->connector); + + recalc |=fanotify_mark_update_flags (fsn_mark, fan_flags);spin_unlock (&fsn_mark->lock); -return newmask & ~oldmask; +return recalc; } static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
@@ -1158,11 +1161,11 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group)static int fanotify_add_mark (struct fsnotify_group *group,fsnotify_connp_t *connp,unsigned int obj_type, -__u32 mask,unsigned int flags, +__u32 mask,unsigned int fan_flags,__kernel_fsid_t *fsid) {struct fsnotify_mark *fsn_mark; -__u32 added, removed =0 ; +bool recalc;int ret =0 ;mutex_lock (&group->mark_mutex);
@@ -1179,14 +1182,14 @@ static int fanotify_add_mark(struct fsnotify_group *group,* Error events are pre-allocated per group, only if strictly * needed (i.e. FAN_FS_ERROR was requested). */ -if (!(flags &FAN_MARK_IGNORED_MASK ) && (mask &FAN_FS_ERROR )) { +if (!(fan_flags &FAN_MARK_IGNORED_MASK ) && (mask &FAN_FS_ERROR )) { ret =fanotify_group_init_error_pool (group);if (ret) goto out; } - added =fanotify_mark_add_to_mask (fsn_mark, mask, flags, &removed); -if (removed || (added & ~fsnotify_conn_mask (fsn_mark->connector))) + recalc =fanotify_mark_add_to_mask (fsn_mark, mask, fan_flags); +if (recalc)fsnotify_recalc_mask (fsn_mark->connector); out:
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 503/770 fanotify: implement "evictable" inode marks
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 7d5e005d982527e4029b0139823d179986e34cdc ]
When an inode mark is created with flag FAN_MARK_EVICTABLE, it will not pin the marked inode to inode cache, so when inode is evicted from cache due to memory pressure, the mark will be lost.
When an inode mark with flag FAN_MARK_EVICATBLE is updated without using this flag, the marked inode is pinned to inode cache.
When an inode mark is updated with flag FAN_MARK_EVICTABLE but an existing mark already has the inode pinned, the mark update fails with error EEXIST.
Evictable inode marks can be used to setup inode marks with ignored mask to suppress events from uninteresting files or directories in a lazy manner, upon receiving the first event, without having to iterate all the uninteresting files or directories before hand.
The evictbale inode mark feature allows performing this lazy marks setup without exhausting the system memory with pinned inodes.
This change does not enable the feature yet.
--- fs/notify/fanotify/fanotify.h | 2 ++ fs/notify/fanotify/fanotify_user.c | 38 ++++++++++++++++++++++++++++-- include/uapi/linux/fanotify.h | 1 + 3 files changed, 39 insertions(+), 2 deletions(-)
fs/notify/fanotify/fanotify.h +2 -0
@@ -497,6 +497,8 @@ static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark)if (mark->flags &FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ) mflags |=FAN_MARK_IGNORED_SURV_MODIFY ; +if (mark->flags &FSNOTIFY_MARK_FLAG_NO_IREF ) + mflags |=FAN_MARK_EVICTABLE ;return mflags; }
fs/notify/fanotify/fanotify_user.c +36 -2
@@ -1072,6 +1072,7 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,static bool fanotify_mark_update_flags (struct fsnotify_mark *fsn_mark,unsigned int fan_flags) { +bool want_iref = !(fan_flags &FAN_MARK_EVICTABLE );bool recalc = false;/*
@@ -1087,7 +1088,18 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark, recalc = true; } -return recalc; +if (fsn_mark->connector->type !=FSNOTIFY_OBJ_TYPE_INODE || + want_iref == !(fsn_mark->flags &FSNOTIFY_MARK_FLAG_NO_IREF )) +return recalc; + +/* +* NO_IREF may be removed from a mark, but not added. +* When removed, fsnotify_recalc_mask() will take the inode ref. +*/ +WARN_ON_ONCE (!want_iref); + fsn_mark->flags &= ~FSNOTIFY_MARK_FLAG_NO_IREF ; + +return true; } static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
@@ -1113,6 +1125,7 @@ static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,static struct fsnotify_mark *fanotify_add_new_mark (struct fsnotify_group *group,fsnotify_connp_t *connp,unsigned int obj_type, +unsigned int fan_flags,__kernel_fsid_t *fsid) {struct ucounts *ucounts = group->fanotify_data.ucounts;
@@ -1135,6 +1148,9 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, }fsnotify_init_mark (mark, group); +if (fan_flags &FAN_MARK_EVICTABLE ) + mark->flags |=FSNOTIFY_MARK_FLAG_NO_IREF ; + ret =fsnotify_add_mark_locked (mark, connp, obj_type,0 , fsid);if (ret) {fsnotify_put_mark (mark);
@@ -1171,13 +1187,23 @@ static int fanotify_add_mark(struct fsnotify_group *group,mutex_lock (&group->mark_mutex); fsn_mark =fsnotify_find_mark (connp, group);if (!fsn_mark) { - fsn_mark =fanotify_add_new_mark (group, connp, obj_type, fsid); + fsn_mark =fanotify_add_new_mark (group, connp, obj_type, + fan_flags, fsid);if (IS_ERR (fsn_mark)) {mutex_unlock (&group->mark_mutex);return PTR_ERR (fsn_mark); } } +/* +* Non evictable mark cannot be downgraded to evictable mark. +*/ +if (fan_flags &FAN_MARK_EVICTABLE && + !(fsn_mark->flags &FSNOTIFY_MARK_FLAG_NO_IREF )) { + ret = -EEXIST ; + goto out; + } +/* * Error events are pre-allocated per group, only if strictly * needed (i.e. FAN_FS_ERROR was requested).
@@ -1607,6 +1633,14 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, mark_type != FAN_MARK_FILESYSTEM) goto fput_and_out; +/* +* Evictable is only relevant for inode marks, because only inode object +* can be evicted on memory pressure. +*/ +if (flags &FAN_MARK_EVICTABLE && + mark_type !=FAN_MARK_INODE ) + goto fput_and_out; +/* * Events that do not carry enough information to report * event->fd require a group that supports reporting fid. Those
include/uapi/linux/fanotify.h +1 -0
@@ -82,6 +82,7 @@#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040#define FAN_MARK_FLUSH 0x00000080/* FAN_MARK_FILESYSTEM is 0x00000100 */ +#define FAN_MARK_EVICTABLE 0x00000200/* These are NOT bitwise flags. Both bits can be used togther. */ #define FAN_MARK_INODE 0x00000000
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 504/770 fanotify: use fsnotify group lock helpers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit e79719a2ca5c61912c0493bc1367db52759cf6fd ]
Direct reclaim from fanotify mark allocation context may try to evict inodes with evictable marks of the same group and hit this deadlock:
[<0>] fsnotify_destroy_mark+0x1f/0x3a [<0>] fsnotify_destroy_marks+0x71/0xd9 [<0>] __destroy_inode+0x24/0x7e [<0>] destroy_inode+0x2c/0x67 [<0>] dispose_list+0x49/0x68 [<0>] prune_icache_sb+0x5b/0x79 [<0>] super_cache_scan+0x11c/0x16f [<0>] shrink_slab.constprop.0+0x23e/0x40f [<0>] shrink_node+0x218/0x3e7 [<0>] do_try_to_free_pages+0x12a/0x2d2 [<0>] try_to_free_pages+0x166/0x242 [<0>] __alloc_pages_slowpath.constprop.0+0x30c/0x903 [<0>] __alloc_pages+0xeb/0x1c7 [<0>] cache_grow_begin+0x6f/0x31e [<0>] fallback_alloc+0xe0/0x12d [<0>] ____cache_alloc_node+0x15a/0x17e [<0>] kmem_cache_alloc_trace+0xa1/0x143 [<0>] fanotify_add_mark+0xd5/0x2b2 [<0>] do_fanotify_mark+0x566/0x5eb [<0>] __x64_sys_fanotify_mark+0x21/0x24 [<0>] do_syscall_64+0x6d/0x80 [<0>] entry_SYSCALL_64_after_hwframe+0x44/0xae
Set the FSNOTIFY_GROUP_NOFS flag to prevent going into direct reclaim from allocations under fanotify group lock and use the safe group lock helpers.
--- fs/notify/fanotify/fanotify_user.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
fs/notify/fanotify/fanotify_user.c +7 -7
@@ -1023,10 +1023,10 @@ static int fanotify_remove_mark(struct fsnotify_group *group,__u32 removed;int destroy_mark; -mutex_lock (&group->mark_mutex); +fsnotify_group_lock (group); fsn_mark =fsnotify_find_mark (connp, group);if (!fsn_mark) { -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group);return -ENOENT ; }
@@ -1036,7 +1036,7 @@ static int fanotify_remove_mark(struct fsnotify_group *group,fsnotify_recalc_mask (fsn_mark->connector);if (destroy_mark)fsnotify_detach_mark (fsn_mark); -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group);if (destroy_mark)fsnotify_free_mark (fsn_mark);
@@ -1184,13 +1184,13 @@ static int fanotify_add_mark(struct fsnotify_group *group,bool recalc;int ret =0 ; -mutex_lock (&group->mark_mutex); +fsnotify_group_lock (group); fsn_mark =fsnotify_find_mark (connp, group);if (!fsn_mark) { fsn_mark =fanotify_add_new_mark (group, connp, obj_type, fan_flags, fsid);if (IS_ERR (fsn_mark)) { -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group);return PTR_ERR (fsn_mark); } }
@@ -1219,7 +1219,7 @@ static int fanotify_add_mark(struct fsnotify_group *group,fsnotify_recalc_mask (fsn_mark->connector); out: -mutex_unlock (&group->mark_mutex); +fsnotify_group_unlock (group);fsnotify_put_mark (fsn_mark);return ret;
@@ -1373,7 +1373,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)/* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ group =fsnotify_alloc_group (&fanotify_fsnotify_ops, -FSNOTIFY_GROUP_USER ); +FSNOTIFY_GROUP_USER |FSNOTIFY_GROUP_NOFS );if (IS_ERR (group)) {return PTR_ERR (group); }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 505/770 fanotify: enable "evictable" inode marks
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 5f9d3bd520261fd7a850818c71809fd580e0f30c ]
Now that the direct reclaim path is handled we can enable evictable inode marks.
--- fs/notify/fanotify/fanotify_user.c | 2 +- include/linux/fanotify.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-)
fs/notify/fanotify/fanotify_user.c +1 -1
@@ -1806,7 +1806,7 @@ static int __init fanotify_user_setup(void)BUILD_BUG_ON (FANOTIFY_INIT_FLAGS &FANOTIFY_INTERNAL_GROUP_FLAGS );BUILD_BUG_ON (HWEIGHT32 (FANOTIFY_INIT_FLAGS ) !=12 ); -BUILD_BUG_ON (HWEIGHT32 (FANOTIFY_MARK_FLAGS ) !=9 ); +BUILD_BUG_ON (HWEIGHT32 (FANOTIFY_MARK_FLAGS ) !=10 ); fanotify_mark_cache =KMEM_CACHE (fsnotify_mark,SLAB_PANIC |SLAB_ACCOUNT );
include/linux/fanotify.h +1 -0
@@ -68,6 +68,7 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */FAN_MARK_ONLYDIR | \FAN_MARK_IGNORED_MASK | \FAN_MARK_IGNORED_SURV_MODIFY | \ +FAN_MARK_EVICTABLE | \ FAN_MARK_FLUSH)/*
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 506/770 fsnotify: introduce mark type iterator
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 14362a2541797cf9df0e86fb12dcd7950baf566e ]
fsnotify_foreach_iter_mark_type() is used to reduce boilerplate code of iterating all marks of a specific group interested in an event by consulting the iterator report_mask.
Use an open coded version of that iterator in fsnotify_iter_next() that collects all marks of the current iteration group without consulting the iterator report_mask.
At the moment, the two iterator variants are the same, but this decoupling will allow us to exclude some of the group's marks from reporting the event, for example for event on child and inode marks on parent did not request to watch events on children.
--- fs/notify/fanotify/fanotify.c | 14 +++------ fs/notify/fsnotify.c | 53 ++++++++++++++++---------------- include/linux/fsnotify_backend.h | 31 ++++++++++++++----- 3 files changed, 54 insertions(+), 44 deletions(-)
fs/notify/fanotify/fanotify.c +4 -10
@@ -319,11 +319,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,return 0 ; } -fsnotify_foreach_iter_type (type) { -if (!fsnotify_iter_should_report_type (iter_info, type)) -continue ; - mark = iter_info->marks[type]; - + fsnotify_foreach_iter_mark_type(iter_info, mark, type) {/* Apply ignore mask regardless of ISDIR and ON_CHILD flags */ marks_ignored_mask |= mark->ignored_mask;
@@ -849,16 +845,14 @@ static struct fanotify_event *fanotify_alloc_event(*/ static __kernel_fsid_t fanotify_get_fsid (struct fsnotify_iter_info *iter_info) { +struct fsnotify_mark *mark;int type;__kernel_fsid_t fsid = {}; -fsnotify_foreach_iter_type (type) { + fsnotify_foreach_iter_mark_type(iter_info, mark, type) {struct fsnotify_mark_connector *conn; -if (!fsnotify_iter_should_report_type (iter_info, type)) -continue ; - - conn =READ_ONCE (iter_info->marks[type]->connector); + conn =READ_ONCE (mark->connector);/* Mark is just getting destroyed or created? */ if (!conn)continue ;
fs/notify/fsnotify.c +26 -27
98 lines not on this page · raw message
include/linux/fsnotify_backend.h +24 -7
@@ -399,6 +399,7 @@ static inline bool fsnotify_valid_obj_type(unsigned int obj_type)struct fsnotify_iter_info {struct fsnotify_mark *marks[FSNOTIFY_ITER_TYPE_COUNT ]; +struct fsnotify_group *current_group;unsigned int report_mask;int srcu_idx; };
@@ -415,20 +416,31 @@ static inline void fsnotify_iter_set_report_type( iter_info->report_mask |= (1U << iter_type); } -static inline void fsnotify_iter_set_report_type_mark ( -struct fsnotify_iter_info *iter_info,int iter_type, -struct fsnotify_mark *mark) +static inline struct fsnotify_mark *fsnotify_iter_mark ( +struct fsnotify_iter_info *iter_info,int iter_type) { - iter_info->marks[iter_type] = mark; - iter_info->report_mask |= (1U << iter_type); +if (fsnotify_iter_should_report_type (iter_info, iter_type)) +return iter_info->marks[iter_type]; +return NULL ; +} + +static inline int fsnotify_iter_step (struct fsnotify_iter_info *iter,int type, +struct fsnotify_mark **markp) +{ +while (type <FSNOTIFY_ITER_TYPE_COUNT ) { + *markp =fsnotify_iter_mark (iter, type); +if (*markp) +break ; + type++; + } +return type; }#define FSNOTIFY_ITER_FUNCS (name,NAME ) \ static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \ struct fsnotify_iter_info *iter_info) \ { \ - return (iter_info->report_mask & (1U << FSNOTIFY_ITER_TYPE_##NAME)) ? \ - iter_info->marks[FSNOTIFY_ITER_TYPE_##NAME] : NULL; \ + return fsnotify_iter_mark(iter_info, FSNOTIFY_ITER_TYPE_##NAME); \ }FSNOTIFY_ITER_FUNCS (inode,INODE )
@@ -438,6 +450,11 @@ FSNOTIFY_ITER_FUNCS(sb, SB)#define fsnotify_foreach_iter_type (type) \ for (type = 0; type < FSNOTIFY_ITER_TYPE_COUNT; type++) +#define fsnotify_foreach_iter_mark_type (iter, mark, type) \ + for (type = 0; \ + type = fsnotify_iter_step(iter, type, &mark), \ + type < FSNOTIFY_ITER_TYPE_COUNT; \ + type++)/* * fsnotify_connp_t is what we embed in objects which connector can be attached
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 507/770 fsnotify: consistent behavior for parent not watching children
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit e730558adffb88a52e562db089e969ee9510184a ]
The logic for handling events on child in groups that have a mark on the parent inode, but without FS_EVENT_ON_CHILD flag in the mask is duplicated in several places and inconsistent.
Move the logic into the preparation of mark type iterator, so that the parent mark type will be excluded from all mark type iterations in that case.
This results in several subtle changes of behavior, hopefully all desired changes of behavior, for example:
- Group A has a mount mark with FS_MODIFY in mask
- Group A has a mark with ignore mask that does not survive FS_MODIFY and does not watch children on directory D.
- Group B has a mark with FS_MODIFY in mask that does watch children on directory D.
- FS_MODIFY event on file D/foo should not clear the ignore mask of group A, but before this change it does
And if group A ignore mask was set to survive FS_MODIFY:
- FS_MODIFY event on file D/foo should be reported to group A on account of the mount mark, but before this change it is wrongly ignored
--- fs/notify/fanotify/fanotify.c | 10 +--------- fs/notify/fsnotify.c | 34 +++++++++++++++++++--------------- 2 files changed, 20 insertions(+), 24 deletions(-)
fs/notify/fanotify/fanotify.c +1 -9
@@ -320,7 +320,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, } fsnotify_foreach_iter_mark_type(iter_info, mark, type) { -/* Apply ignore mask regardless of ISDIR and ON_CHILD flags */ +/* Apply ignore mask regardless of mark's ISDIR flag */ marks_ignored_mask |= mark->ignored_mask;/*
@@ -330,14 +330,6 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,if (event_mask &FS_ISDIR && !(mark->mask &FS_ISDIR ))continue ; -/* -* If the event is on a child and this mark is on a parent not -* watching children, don't send it! -*/ -if (type ==FSNOTIFY_ITER_TYPE_PARENT && - !(mark->mask &FS_EVENT_ON_CHILD )) -continue ; - marks_mask |= mark->mask;/* Record the mark types of this group that matched the event */
fs/notify/fsnotify.c +19 -15
@@ -290,22 +290,15 @@ static int fsnotify_handle_event(struct fsnotify_group *group, __u32 mask, }if (parent_mark) { -/* -* parent_mark indicates that the parent inode is watching -* children and interested in this event, which is an event -* possible on child. But is *this mark* watching children and -* interested in this event? -*/ -if (parent_mark->mask &FS_EVENT_ON_CHILD ) { - ret =fsnotify_handle_inode_event (group, parent_mark, mask, - data, data_type, dir, name,0 ); -if (ret) -return ret; - } -if (!inode_mark) -return 0 ; + ret =fsnotify_handle_inode_event (group, parent_mark, mask, + data, data_type, dir, name,0 ); +if (ret) +return ret; } +if (!inode_mark) +return 0 ; +if (mask &FS_EVENT_ON_CHILD ) {/* * Some events can be sent on both parent dir and child marks
@@ -422,8 +415,19 @@ static bool fsnotify_iter_select_report_types( iter_info->report_mask =0 ;fsnotify_foreach_iter_type (type) { mark = iter_info->marks[type]; -if (mark && mark->group == iter_info->current_group) +if (mark && mark->group == iter_info->current_group) { +/* +* FSNOTIFY_ITER_TYPE_PARENT indicates that this inode +* is watching children and interested in this event, +* which is an event possible on child. +* But is *this mark* watching children? +*/ +if (type ==FSNOTIFY_ITER_TYPE_PARENT && + !(mark->mask &FS_EVENT_ON_CHILD )) +continue ; +fsnotify_iter_set_report_type (iter_info, type); + } }return true;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 508/770 fanotify: fix incorrect fmode_t casts
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasily Averin <[email protected]>
[ Upstream commit dccd855771b37820b6d976a99729c88259549f85 ]
Fixes sparce warnings:fs/notify/fanotify/fanotify_user.c:267:63: sparse:
warning: restricted fmode_t degrades to integerfs/notify/fanotify/fanotify_user.c:1351:28: sparse:
warning: restricted fmode_t degrades to integer
FMODE_NONTIFY have bitwise fmode_t type and requires __force attribute for any casts.
--- fs/notify/fanotify/fanotify_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/notify/fanotify/fanotify_user.c +2 -2
@@ -252,7 +252,7 @@ static int create_fd(struct fsnotify_group *group, struct path *path,* originally opened O_WRONLY. */ new_file =dentry_open (path, - group->fanotify_data.f_flags |FMODE_NONOTIFY , + group->fanotify_data.f_flags | __FMODE_NONOTIFY,current_cred ());if (IS_ERR (new_file)) {/*
@@ -1365,7 +1365,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) (!(fid_mode & FAN_REPORT_NAME) || !(fid_mode & FAN_REPORT_FID)))return -EINVAL ; - f_flags =O_RDWR |FMODE_NONOTIFY ; + f_flags =O_RDWR | __FMODE_NONOTIFY;if (flags &FAN_CLOEXEC ) f_flags |=O_CLOEXEC ;if (flags &FAN_NONBLOCK )
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 509/770 NFSD: Clean up nfsd_splice_actor()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 91e23b1c39820bfed642119ff6b6ef9f43cf09ce ]
nfsd_splice_actor() checks that the page being spliced does not match the previous element in the svc_rqst::rq_pages array. We believe this is to prevent a double put_page() in cases where the READ payload is partially contained in the xdr_buf's head buffer.
However, the NFSD READ proc functions no longer place any part of the READ payload in the head buffer, in order to properly support NFS/RDMA READ with Write chunks. Therefore, simplify the logic in nfsd_splice_actor() to remove this unnecessary check.
--- fs/nfsd/vfs.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
fs/nfsd/vfs.c +2 -8
@@ -874,17 +874,11 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct splice_desc *sd) {struct svc_rqst *rqstp = sd->u.data; -struct page **pp = rqstp->rq_next_page; -struct page *page = buf->page; -if (rqstp->rq_res.page_len ==0 ) { -svc_rqst_replace_page (rqstp, page); +svc_rqst_replace_page (rqstp, buf->page); +if (rqstp->rq_res.page_len ==0 ) rqstp->rq_res.page_base = buf->offset; - }else if (page != pp[-1 ]) { -svc_rqst_replace_page (rqstp, page); - } rqstp->rq_res.page_len += sd->len; -return sd->len; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 510/770 NFSD: add courteous server support for thread with only delegation
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit 66af25799940b26efd41ea6e648f75c41a48a2c2 ]
This patch provides courteous server support for delegation only. Only expired client with delegation but no conflict and no open or lock state is allowed to be in COURTESY state.
Delegation conflict with COURTESY/EXPIRABLE client is resolved by setting it to EXPIRABLE, queue work for the laundromat and return delay to the caller. Conflict is resolved when the laudromat runs and expires the EXIRABLE client while the NFS client retries the OPEN request. Local thread request that gets conflict is doing the retry in _break_lease.
Client in COURTESY or EXPIRABLE state is allowed to reconnect and continues to have access to its state. Access to the nfs4_client by the reconnecting thread and the laundromat is serialized via the client_lock.
--- fs/nfsd/nfs4state.c | 82 ++++++++++++++++++++++++++++++++++++--------- fs/nfsd/nfsd.h | 1 + fs/nfsd/state.h | 31 +++++++++++++++++ 3 files changed, 99 insertions(+), 15 deletions(-)
fs/nfsd/nfs4state.c +67 -15
@@ -125,6 +125,8 @@ static void free_session(struct nfsd4_session *);static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; +static struct workqueue_struct *laundry_wq; +static bool is_session_dead (struct nfsd4_session *ses) {return ses->se_flags &NFS4_SESSION_DEAD ;
@@ -152,6 +154,7 @@ static __be32 get_client_locked(struct nfs4_client *clp)if (is_client_expired (clp))return nfserr_expired;atomic_inc (&clp->cl_rpc_users); + clp->cl_state =NFSD4_ACTIVE ;return nfs_ok; }
@@ -172,6 +175,7 @@ renew_client_locked(struct nfs4_client *clp)list_move_tail (&clp->cl_lru, &nn->client_lru); clp->cl_time =ktime_get_boottime_seconds (); + clp->cl_state =NFSD4_ACTIVE ; }static void put_client_renew_locked (struct nfs4_client *clp)
@@ -1102,6 +1106,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,get_clnt_odstate (odstate); dp->dl_type =NFS4_OPEN_DELEGATE_READ ; dp->dl_retries =1 ; + dp->dl_recalled = false;nfsd4_init_cb (&dp->dl_recall, dp->dl_stid.sc_client, &nfsd4_cb_recall_ops,NFSPROC4_CLNT_CB_RECALL );get_nfs4_file (fp);
@@ -2017,6 +2022,8 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)idr_init (&clp->cl_stateids);atomic_set (&clp->cl_rpc_users,0 ); clp->cl_cb_state =NFSD4_CB_UNKNOWN ; + clp->cl_state =NFSD4_ACTIVE ; +atomic_set (&clp->cl_delegs_in_recall,0 );INIT_LIST_HEAD (&clp->cl_idhash);INIT_LIST_HEAD (&clp->cl_openowners);INIT_LIST_HEAD (&clp->cl_delegations);
@@ -4711,9 +4718,18 @@ nfsd_break_deleg_cb(struct file_lock *fl)bool ret = false;struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;struct nfs4_file *fp = dp->dl_stid.sc_file; +struct nfs4_client *clp = dp->dl_stid.sc_client; +struct nfsd_net *nn;trace_nfsd_cb_recall (&dp->dl_stid); + dp->dl_recalled = true; +atomic_inc (&clp->cl_delegs_in_recall); +if (try_to_expire_client (clp)) { + nn =net_generic (clp->net, nfsd_net_id); +mod_delayed_work (laundry_wq, &nn->laundromat_work,0 ); + } +/* * We don't want the locks code to timeout the lease for us; * we'll remove it ourself if a delegation isn't returned
@@ -4756,9 +4772,14 @@ static int nfsd_change_deleg_cb(struct file_lock *onlist, int arg, struct list_head *dispose) { - if (arg & F_UNLCK) + struct nfs4_delegation *dp = (struct nfs4_delegation *)onlist->fl_owner; +struct nfs4_client *clp = dp->dl_stid.sc_client; + +if (arg &F_UNLCK ) { +if (dp->dl_recalled) +atomic_dec (&clp->cl_delegs_in_recall);return lease_modify (onlist, arg, dispose); - else + }else return -EAGAIN ; }
@@ -5622,6 +5643,49 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) }#endif +/* +* place holder for now, no check for lock blockers yet +*/ +static bool +nfs4_anylock_blockers (struct nfs4_client *clp) +{ +if (atomic_read (&clp->cl_delegs_in_recall) || +client_has_openowners (clp) || + !list_empty (&clp->async_copies)) +return true; +return false; +} + +static void +nfs4_get_client_reaplist (struct nfsd_net *nn,struct list_head *reaplist, +struct laundry_time *lt) +{ +struct list_head *pos, *next; +struct nfs4_client *clp; + +INIT_LIST_HEAD (reaplist); +spin_lock (&nn->client_lock); +list_for_each_safe (pos, next, &nn->client_lru) { + clp = list_entry(pos, struct nfs4_client, cl_lru); +if (clp->cl_state ==NFSD4_EXPIRABLE ) + goto exp_client; +if (!state_expired (lt, clp->cl_time)) +break ; +if (!atomic_read (&clp->cl_rpc_users)) + clp->cl_state =NFSD4_COURTESY ; +if (!client_has_state (clp) || +ktime_get_boottime_seconds () >= + (clp->cl_time +NFSD_COURTESY_CLIENT_TIMEOUT )) + goto exp_client; +if (nfs4_anylock_blockers (clp)) { +exp_client: +if (!mark_client_expired_locked (clp)) +list_add (&clp->cl_lru, reaplist); + } + } +spin_unlock (&nn->client_lock); +} +static time64_t nfs4_laundromat (struct nfsd_net *nn) {
@@ -5644,7 +5708,6 @@ nfs4_laundromat(struct nfsd_net *nn) goto out; }nfsd4_end_grace (nn); -INIT_LIST_HEAD (&reaplist);spin_lock (&nn->s2s_cp_lock);idr_for_each_entry (&nn->s2s_cp_stateids, cps_t, i) {
@@ -5654,17 +5717,7 @@ nfs4_laundromat(struct nfsd_net *nn)_free_cpntf_state_locked (nn, cps); }spin_unlock (&nn->s2s_cp_lock); - -spin_lock (&nn->client_lock); -list_for_each_safe (pos, next, &nn->client_lru) { - clp = list_entry(pos, struct nfs4_client, cl_lru); -if (!state_expired (<, clp->cl_time)) -break ; -if (mark_client_expired_locked (clp)) -continue ; -list_add (&clp->cl_lru, &reaplist); - } -spin_unlock (&nn->client_lock); +nfs4_get_client_reaplist (nn, &reaplist, <);list_for_each_safe (pos, next, &reaplist) { clp = list_entry(pos, struct nfs4_client, cl_lru);trace_nfsd_clid_purged (&clp->cl_clientid);
@@ -5739,7 +5792,6 @@ nfs4_laundromat(struct nfsd_net *nn)return max_t (time64_t, lt.new_timeo,NFSD_LAUNDROMAT_MINTIMEOUT ); } -static struct workqueue_struct *laundry_wq;static void laundromat_main (struct work_struct *); static void
fs/nfsd/nfsd.h +1 -0
@@ -336,6 +336,7 @@ void nfsd_lockd_shutdown(void);#define COMPOUND_ERR_SLACK_SPACE 16/* OP_SETATTR */ #define NFSD_LAUNDROMAT_MINTIMEOUT 1/* seconds */ +#define NFSD_COURTESY_CLIENT_TIMEOUT (24 * 60 * 60)/* seconds */ /* * The following attributes are currently not supported by the NFSv4 server:
fs/nfsd/state.h +31 -0
@@ -149,6 +149,7 @@ struct nfs4_delegation {/* For recall: */ int dl_retries;struct nfsd4_callback dl_recall; +bool dl_recalled; };#define cb_to_delegation (cb) \
@@ -282,6 +283,28 @@ struct nfsd4_sessionid {#define HEXDIR_LEN 33/* hex version of 16 byte md5 of cl_name plus '\0' */ +/* +* State Meaning Where set +* -------------------------------------------------------------------------- +* | NFSD4_ACTIVE | Confirmed, active | Default | +* |------------------- ----------------------------------------------------| +* | NFSD4_COURTESY | Courtesy state. | nfs4_get_client_reaplist | +* | | Lease/lock/share | | +* | | reservation conflict | | +* | | can cause Courtesy | | +* | | client to be expired | | +* |------------------------------------------------------------------------| +* | NFSD4_EXPIRABLE | Courtesy client to be| nfs4_laundromat | +* | | expired by Laundromat| try_to_expire_client | +* | | due to conflict | | +* |------------------------------------------------------------------------| +*/ +enum { +NFSD4_ACTIVE =0 , +NFSD4_COURTESY , +NFSD4_EXPIRABLE , +}; +/* * struct nfs4_client - one per client. Clientids live here. *
@@ -385,6 +408,9 @@ struct nfs4_client {struct list_head async_copies;/* list of async copies */ spinlock_t async_lock;/* lock for async copies */ atomic_t cl_cb_inflight;/* Outstanding callbacks */ + +unsigned int cl_state; +atomic_t cl_delegs_in_recall; };/* struct nfs4_client_reset
@@ -702,4 +728,9 @@ extern void nfsd4_client_record_remove(struct nfs4_client *clp);extern int nfsd4_client_record_check (struct nfs4_client *clp);extern void nfsd4_record_grace_done (struct nfsd_net *nn); +static inline bool try_to_expire_client (struct nfs4_client *clp) +{ +cmpxchg (&clp->cl_state,NFSD4_COURTESY ,NFSD4_EXPIRABLE ); +return clp->cl_state ==NFSD4_EXPIRABLE ; +}#endif /* NFSD4_STATE_H */
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 511/770 NFSD: add support for share reservation conflict to courteous server
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit 3d69427151806656abf129342028f3f4e5e1fee0 ]
This patch allows expired client with open state to be in COURTESY state. Share/access conflict with COURTESY client is resolved by setting COURTESY client to EXPIRABLE state, schedule laundromat to run and returning nfserr_jukebox to the request client.
--- fs/nfsd/nfs4state.c | 109 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 8 deletions(-)
fs/nfsd/nfs4state.c +101 -8
@@ -705,6 +705,57 @@ static unsigned int file_hashval(struct svc_fh *fh)static struct hlist_head file_hashtbl[FILE_HASH_SIZE ]; +/* +* Check if courtesy clients have conflicting access and resolve it if possible +* +* access: is op_share_access if share_access is true. +* Check if access mode, op_share_access, would conflict with +* the current deny mode of the file 'fp'. +* access: is op_share_deny if share_access is false. +* Check if the deny mode, op_share_deny, would conflict with +* current access of the file 'fp'. +* stp: skip checking this entry. +* new_stp: normal open, not open upgrade. +* +* Function returns: +* false - access/deny mode conflict with normal client. +* true - no conflict or conflict with courtesy client(s) is resolved. +*/ +static bool +nfs4_resolve_deny_conflicts_locked (struct nfs4_file *fp,bool new_stp, +struct nfs4_ol_stateid *stp,u32 access,bool share_access) +{ +struct nfs4_ol_stateid *st; +bool resolvable = true; +unsigned char bmap; +struct nfsd_net *nn; +struct nfs4_client *clp; + +lockdep_assert_held (&fp->fi_lock); +list_for_each_entry (st, &fp->fi_stateids, st_perfile) { +/* ignore lock stateid */ +if (st->st_openstp) +continue ; +if (st == stp && new_stp) +continue ; +/* check file access against deny mode or vice versa */ + bmap = share_access ? st->st_deny_bmap : st->st_access_bmap; +if (!(access &bmap_to_share_mode (bmap))) +continue ; + clp = st->st_stid.sc_client; +if (try_to_expire_client (clp)) +continue ; + resolvable = false; +break ; + } +if (resolvable) { + clp = stp->st_stid.sc_client; + nn =net_generic (clp->net, nfsd_net_id); +mod_delayed_work (laundry_wq, &nn->laundromat_work,0 ); + } +return resolvable; +} +static void __nfs4_file_get_access (struct nfs4_file *fp,u32 access) {
@@ -4985,7 +5036,7 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,static __be32 nfs4_get_vfs_file (struct svc_rqst *rqstp,struct nfs4_file *fp,struct svc_fh *cur_fh,struct nfs4_ol_stateid *stp, -struct nfsd4_open *open) +struct nfsd4_open *open,bool new_stp) {struct nfsd_file *nf =NULL ;__be32 status;
@@ -5001,6 +5052,13 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,*/ status =nfs4_file_check_deny (fp, open->op_share_deny);if (status != nfs_ok) { +if (status != nfserr_share_denied) { +spin_unlock (&fp->fi_lock); + goto out; + } +if (nfs4_resolve_deny_conflicts_locked (fp, new_stp, + stp, open->op_share_deny, false)) + status = nfserr_jukebox;spin_unlock (&fp->fi_lock); goto out; }
@@ -5008,6 +5066,13 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,/* set access to the file */ status =nfs4_file_get_access (fp, open->op_share_access);if (status != nfs_ok) { +if (status != nfserr_share_denied) { +spin_unlock (&fp->fi_lock); + goto out; + } +if (nfs4_resolve_deny_conflicts_locked (fp, new_stp, + stp, open->op_share_access, true)) + status = nfserr_jukebox;spin_unlock (&fp->fi_lock); goto out; }
@@ -5054,21 +5119,29 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, }static __be32 -nfs4_upgrade_open (struct svc_rqst *rqstp,struct nfs4_file *fp,struct svc_fh *cur_fh,struct nfs4_ol_stateid *stp,struct nfsd4_open *open) +nfs4_upgrade_open (struct svc_rqst *rqstp,struct nfs4_file *fp, +struct svc_fh *cur_fh,struct nfs4_ol_stateid *stp, +struct nfsd4_open *open) {__be32 status;unsigned char old_deny_bmap = stp->st_deny_bmap;if (!test_access (open->op_share_access, stp)) -return nfs4_get_vfs_file (rqstp, fp, cur_fh, stp, open); +return nfs4_get_vfs_file (rqstp, fp, cur_fh, stp, open, false);/* test and set deny mode */ spin_lock (&fp->fi_lock); status =nfs4_file_check_deny (fp, open->op_share_deny);if (status == nfs_ok) { -set_deny (open->op_share_deny, stp); - fp->fi_share_deny |= +if (status != nfserr_share_denied) { +set_deny (open->op_share_deny, stp); + fp->fi_share_deny |= (open->op_share_deny &NFS4_SHARE_DENY_BOTH ); + }else { +if (nfs4_resolve_deny_conflicts_locked (fp, false, + stp, open->op_share_deny, false)) + status = nfserr_jukebox; + } }spin_unlock (&fp->fi_lock);
@@ -5409,7 +5482,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf goto out; } }else { - status =nfs4_get_vfs_file (rqstp, fp, current_fh, stp, open); + status =nfs4_get_vfs_file (rqstp, fp, current_fh, stp, open, true);if (status) { stp->st_stid.sc_type =NFS4_CLOSED_STID ;release_open_stateid (stp);
@@ -5643,6 +5716,26 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) }#endif +static bool +nfs4_has_any_locks (struct nfs4_client *clp) +{ +int i; +struct nfs4_stateowner *so; + +spin_lock (&clp->cl_lock); +for (i =0 ; i <OWNER_HASH_SIZE ; i++) { +list_for_each_entry (so, &clp->cl_ownerstr_hashtbl[i], + so_strhash) { +if (so->so_is_open_owner) +continue ; +spin_unlock (&clp->cl_lock); +return true; + } + } +spin_unlock (&clp->cl_lock); +return false; +} +/* * place holder for now, no check for lock blockers yet */
@@ -5650,8 +5743,8 @@ static bool nfs4_anylock_blockers(struct nfs4_client *clp) {if (atomic_read (&clp->cl_delegs_in_recall) || -client_has_openowners (clp) || - !list_empty (&clp->async_copies)) + !list_empty (&clp->async_copies) || +nfs4_has_any_locks (clp))return true;return false; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 512/770 NFSD: move create/destroy of laundry_wq to init_nfsd and exit_nfsd
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit d76cc46b37e123e8d245cc3490978dbda56f979d ]
This patch moves create/destroy of laundry_wq from nfs4_state_start and nfs4_state_shutdown_net to init_nfsd and exit_nfsd to prevent the laundromat from being freed while a thread is processing a conflicting lock.
--- fs/nfsd/nfs4state.c | 28 ++++++++++++++++------------ fs/nfsd/nfsctl.c | 4 ++++ fs/nfsd/nfsd.h | 4 ++++ 3 files changed, 24 insertions(+), 12 deletions(-)
fs/nfsd/nfs4state.c +16 -12
@@ -127,6 +127,21 @@ static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops;static struct workqueue_struct *laundry_wq; +int nfsd4_create_laundry_wq (void ) +{ +int rc =0 ; + + laundry_wq =alloc_workqueue ("%s" ,WQ_UNBOUND ,0 ,"nfsd4" ); +if (laundry_wq ==NULL ) + rc = -ENOMEM ; +return rc; +} + +void nfsd4_destroy_laundry_wq (void ) +{ +destroy_workqueue (laundry_wq); +} +static bool is_session_dead (struct nfsd4_session *ses) {return ses->se_flags &NFS4_SESSION_DEAD ;
@@ -7775,22 +7790,12 @@ nfs4_state_start(void) {int ret; - laundry_wq =alloc_workqueue ("%s" ,WQ_UNBOUND ,0 ,"nfsd4" ); -if (laundry_wq ==NULL ) { - ret = -ENOMEM ; - goto out; - } ret =nfsd4_create_callback_queue ();if (ret) - goto out_free_laundry; +return ret;set_max_delegations ();return 0 ; - -out_free_laundry: -destroy_workqueue (laundry_wq); -out: -return ret; }void
@@ -7827,7 +7832,6 @@ nfs4_state_shutdown_net(struct net *net)void nfs4_state_shutdown (void ) { -destroy_workqueue (laundry_wq);nfsd4_destroy_callback_queue (); }
fs/nfsd/nfsctl.c +4 -0
@@ -1542,6 +1542,9 @@ static int __init init_nfsd(void)if (retval <0 ) goto out_free_filesystem; retval =register_cld_notifier (); +if (retval) + goto out_free_all; + retval =nfsd4_create_laundry_wq ();if (retval) goto out_free_all;return 0 ;
@@ -1566,6 +1569,7 @@ static int __init init_nfsd(void) static void __exit exit_nfsd(void) { +nfsd4_destroy_laundry_wq ();unregister_cld_notifier ();unregister_pernet_subsys (&nfsd_net_ops);nfsd_drc_slab_free ();
fs/nfsd/nfsd.h +4 -0
@@ -162,6 +162,8 @@ void nfs4_state_shutdown_net(struct net *net);int nfs4_reset_recoverydir (char *recdir);char *nfs4_recoverydir (void );bool nfsd4_spo_must_allow (struct svc_rqst *rqstp); +int nfsd4_create_laundry_wq (void ); +void nfsd4_destroy_laundry_wq (void );#else static inline int nfsd4_init_slabs (void ) {return 0 ; }static inline void nfsd4_free_slabs (void ) { }
@@ -175,6 +177,8 @@ static inline bool nfsd4_spo_must_allow(struct svc_rqst *rqstp) {return false; } +static inline int nfsd4_create_laundry_wq (void ) {return 0 ; }; +static inline void nfsd4_destroy_laundry_wq (void ) {};#endif /*
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 513/770 fs/lock: add helper locks_owner_has_blockers to check for blockers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit 591502c5cb325b1c6ec59ab161927d606b918aa0 ]
Add helper locks_owner_has_blockers to check if there is any blockers for a given lockowner.
--- fs/locks.c | 28 ++++++++++++++++++++++++++++ include/linux/fs.h | 7 +++++++ 2 files changed, 35 insertions(+)
fs/locks.c +28 -0
@@ -376,6 +376,34 @@ void locks_release_private(struct file_lock *fl) }EXPORT_SYMBOL_GPL (locks_release_private); +/** +* locks_owner_has_blockers - Check for blocking lock requests +* @flctx: file lock context +* @owner: lock owner +* +* Return values: +* %true: @owner has at least one blocker +* %false: @owner has no blockers +*/ +bool locks_owner_has_blockers (struct file_lock_context *flctx, +fl_owner_t owner) +{ +struct file_lock *fl; + +spin_lock (&flctx->flc_lock); +list_for_each_entry (fl, &flctx->flc_posix, fl_list) { +if (fl->fl_owner != owner) +continue ; +if (!list_empty (&fl->fl_blocked_requests)) { +spin_unlock (&flctx->flc_lock); +return true; + } + } +spin_unlock (&flctx->flc_lock); +return false; +} +EXPORT_SYMBOL_GPL (locks_owner_has_blockers); +/* Free a lock which is not in use. */ void locks_free_lock (struct file_lock *fl) {
include/linux/fs.h +7 -0
@@ -1163,6 +1163,8 @@ extern void lease_unregister_notifier(struct notifier_block *);struct files_struct ;extern void show_fd_locks (struct seq_file *f,struct file *filp,struct files_struct *files); +extern bool locks_owner_has_blockers (struct file_lock_context *flctx, +fl_owner_t owner);#else /* !CONFIG_FILE_LOCKING */ static inline int fcntl_getlk (struct file *file,unsigned int cmd,struct flock __user *user)
@@ -1303,6 +1305,11 @@ static inline int lease_modify(struct file_lock *fl, int arg,struct files_struct ;static inline void show_fd_locks (struct seq_file *f,struct file *filp,struct files_struct *files) {} +static inline bool locks_owner_has_blockers (struct file_lock_context *flctx, +fl_owner_t owner) +{ +return false; +}#endif /* !CONFIG_FILE_LOCKING */ static inline struct inode *file_inode (const struct file *f)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 514/770 fs/lock: add 2 callbacks to lock_manager_operations to resolve conflict
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit 2443da2259e97688f93d64d17ab69b15f466078a ]
Add 2 new callbacks, lm_lock_expirable and lm_expire_lock, to lock_manager_operations to allow the lock manager to take appropriate action to resolve the lock conflict if possible.
A new field, lm_mod_owner, is also added to lock_manager_operations. The lm_mod_owner is used by the fs/lock code to make sure the lock manager module such as nfsd, is not freed while lock conflict is being resolved.
lm_lock_expirable checks and returns true to indicate that the lock conflict can be resolved else return false. This callback must be called with the flc_lock held so it can not block.
lm_expire_lock is called to resolve the lock conflict if the returned value from lm_lock_expirable is true. This callback is called without the flc_lock held since it's allowed to block. Upon returning from this callback, the lock conflict should be resolved and the caller is expected to restart the conflict check from the beginnning of the list.
Lock manager, such as NFSv4 courteous server, uses this callback to resolve conflict by destroying lock owner, or the NFSv4 courtesy client (client that has expired but allowed to maintains its states) that owns the lock.
--- Documentation/filesystems/locking.rst | 4 ++++ fs/locks.c | 33 ++++++++++++++++++++++++--- include/linux/fs.h | 3 +++ 3 files changed, 37 insertions(+), 3 deletions(-)
Documentation/filesystems/locking.rst +4 -0
@@ -433,6 +433,8 @@ prototypes:: void (*lm_break)(struct file_lock *); /* break_lease callback */ int (*lm_change)(struct file_lock **, int); bool (*lm_breaker_owns_lease)(struct file_lock *); + bool (*lm_lock_expirable)(struct file_lock *); + void (*lm_expire_lock)(void); locking rules:
@@ -444,6 +446,8 @@ lm_grant: no no no lm_break: yes no no lm_change yes no no lm_breaker_owns_lease: yes no no +lm_lock_expirable yes no no +lm_expire_lock no no yes ====================== ============= ================= ========= buffer_head
fs/locks.c +30 -3
@@ -982,6 +982,8 @@ posix_test_lock(struct file *filp, struct file_lock *fl)struct file_lock *cfl;struct file_lock_context *ctx;struct inode *inode =locks_inode (filp); +void *owner; +void (*func)(void ); ctx =smp_load_acquire (&inode->i_flctx);if (!ctx ||list_empty_careful (&ctx->flc_posix)) {
@@ -989,12 +991,23 @@ posix_test_lock(struct file *filp, struct file_lock *fl)return ; } +retry:spin_lock (&ctx->flc_lock);list_for_each_entry (cfl, &ctx->flc_posix, fl_list) { -if (posix_locks_conflict (fl, cfl)) { -locks_copy_conflock (fl, cfl); - goto out; +if (!posix_locks_conflict (fl, cfl)) +continue ; +if (cfl->fl_lmops && cfl->fl_lmops->lm_lock_expirable + && (*cfl->fl_lmops->lm_lock_expirable)(cfl)) { + owner = cfl->fl_lmops->lm_mod_owner; + func = cfl->fl_lmops->lm_expire_lock; +__module_get (owner); +spin_unlock (&ctx->flc_lock); + (*func)(); +module_put (owner); + goto retry; } +locks_copy_conflock (fl, cfl); + goto out; } fl->fl_type =F_UNLCK ; out:
@@ -1168,6 +1181,8 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,int error;bool added = false;LIST_HEAD (dispose); +void *owner; +void (*func)(void ); ctx =locks_get_lock_context (inode, request->fl_type);if (!ctx)
@@ -1186,6 +1201,7 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request, new_fl2 =locks_alloc_lock (); } +retry:percpu_down_read (&file_rwsem);spin_lock (&ctx->flc_lock);/*
@@ -1197,6 +1213,17 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,list_for_each_entry (fl, &ctx->flc_posix, fl_list) {if (!posix_locks_conflict (request, fl))continue ; +if (fl->fl_lmops && fl->fl_lmops->lm_lock_expirable + && (*fl->fl_lmops->lm_lock_expirable)(fl)) { + owner = fl->fl_lmops->lm_mod_owner; + func = fl->fl_lmops->lm_expire_lock; +__module_get (owner); +spin_unlock (&ctx->flc_lock); +percpu_up_read (&file_rwsem); + (*func)(); +module_put (owner); + goto retry; + }if (conflock)locks_copy_conflock (conflock, fl); error = -EAGAIN ;
include/linux/fs.h +3 -0
@@ -1017,6 +1017,7 @@ struct file_lock_operations { };struct lock_manager_operations { +void *lm_mod_owner;fl_owner_t (*lm_get_owner)(fl_owner_t );void (*lm_put_owner)(fl_owner_t );void (*lm_notify)(struct file_lock *);/* unblock callback */
@@ -1025,6 +1026,8 @@ struct lock_manager_operations {int (*lm_change)(struct file_lock *,int ,struct list_head *);void (*lm_setup)(struct file_lock *,void **);bool (*lm_breaker_owns_lease)(struct file_lock *); +bool (*lm_lock_expirable)(struct file_lock *cfl); +void (*lm_expire_lock)(void ); };struct lock_manager {
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 515/770 NFSD: add support for lock conflict to courteous server
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit 27431affb0dbc259ac6ffe6071243a576c8f38f1 ]
This patch allows expired client with lock state to be in COURTESY state. Lock conflict with COURTESY client is resolved by the fs/lock code using the lm_lock_expirable and lm_expire_lock callback in the struct lock_manager_operations.
If conflict client is in COURTESY state, set it to EXPIRABLE and schedule the laundromat to run immediately to expire the client. The callback lm_expire_lock waits for the laundromat to flush its work queue before returning to caller.
--- fs/nfsd/nfs4state.c | 70 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 16 deletions(-)
fs/nfsd/nfs4state.c +54 -16
@@ -5731,39 +5731,51 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) }#endif +/* Check if any lock belonging to this lockowner has any blockers */ static bool -nfs4_has_any_locks (struct nfs4_client *clp) +nfs4_lockowner_has_blockers (struct nfs4_lockowner *lo) +{ +struct file_lock_context *ctx; +struct nfs4_ol_stateid *stp; +struct nfs4_file *nf; + +list_for_each_entry (stp, &lo->lo_owner.so_stateids, st_perstateowner) { + nf = stp->st_stid.sc_file; + ctx = nf->fi_inode->i_flctx; +if (!ctx) +continue ; +if (locks_owner_has_blockers (ctx, lo)) +return true; + } +return false; +} + +static bool +nfs4_anylock_blockers (struct nfs4_client *clp) {int i;struct nfs4_stateowner *so; +struct nfs4_lockowner *lo; +if (atomic_read (&clp->cl_delegs_in_recall)) +return true;spin_lock (&clp->cl_lock);for (i =0 ; i <OWNER_HASH_SIZE ; i++) {list_for_each_entry (so, &clp->cl_ownerstr_hashtbl[i], so_strhash) {if (so->so_is_open_owner)continue ; -spin_unlock (&clp->cl_lock); -return true; + lo =lockowner (so); +if (nfs4_lockowner_has_blockers (lo)) { +spin_unlock (&clp->cl_lock); +return true; + } } }spin_unlock (&clp->cl_lock);return false; } -/* -* place holder for now, no check for lock blockers yet -*/ -static bool -nfs4_anylock_blockers (struct nfs4_client *clp) -{ -if (atomic_read (&clp->cl_delegs_in_recall) || - !list_empty (&clp->async_copies) || -nfs4_has_any_locks (clp)) -return true; -return false; -} -static void nfs4_get_client_reaplist (struct nfsd_net *nn,struct list_head *reaplist,struct laundry_time *lt)
@@ -6743,6 +6755,29 @@ nfsd4_lm_put_owner(fl_owner_t owner)nfs4_put_stateowner (&lo->lo_owner); } +/* return pointer to struct nfs4_client if client is expirable */ +static bool +nfsd4_lm_lock_expirable (struct file_lock *cfl) +{ +struct nfs4_lockowner *lo = (struct nfs4_lockowner *)cfl->fl_owner; +struct nfs4_client *clp = lo->lo_owner.so_client; +struct nfsd_net *nn; + +if (try_to_expire_client (clp)) { + nn =net_generic (clp->net, nfsd_net_id); +mod_delayed_work (laundry_wq, &nn->laundromat_work,0 ); +return true; + } +return false; +} + +/* schedule laundromat to run immediately and wait for it to complete */ +static void +nfsd4_lm_expire_lock (void ) +{ +flush_workqueue (laundry_wq); +} +static void nfsd4_lm_notify (struct file_lock *fl) {
@@ -6769,9 +6804,12 @@ nfsd4_lm_notify(struct file_lock *fl) }static const struct lock_manager_operations nfsd_posix_mng_ops = { + .lm_mod_owner =THIS_MODULE , .lm_notify = nfsd4_lm_notify, .lm_get_owner = nfsd4_lm_get_owner, .lm_put_owner = nfsd4_lm_put_owner, + .lm_lock_expirable = nfsd4_lm_lock_expirable, + .lm_expire_lock = nfsd4_lm_expire_lock, }; static inline void
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 516/770 NFSD: Show state of courtesy client in client info
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit e9488d5ae13c0a72223c507e2508dc2ac66cad4f ]
Update client_info_show to show state of courtesy client and seconds since last renew.
--- fs/nfsd/nfs4state.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
fs/nfsd/nfs4state.c +8 -1
@@ -2494,10 +2494,17 @@ static int client_info_show(struct seq_file *m, void *v)memcpy (&clid, &clp->cl_clientid,sizeof (clid));seq_printf (m,"clientid: 0x%llx\n" , clid);seq_printf (m,"address: \"%pISpc\"\n" , (struct sockaddr *)&clp->cl_addr); -if (test_bit (NFSD4_CLIENT_CONFIRMED , &clp->cl_flags)) + +if (clp->cl_state ==NFSD4_COURTESY ) +seq_puts (m,"status: courtesy\n" ); +else if (clp->cl_state ==NFSD4_EXPIRABLE ) +seq_puts (m,"status: expirable\n" ); +else if (test_bit (NFSD4_CLIENT_CONFIRMED , &clp->cl_flags))seq_puts (m,"status: confirmed\n" );else seq_puts (m,"status: unconfirmed\n" ); +seq_printf (m,"seconds from last renew: %lld\n" , +ktime_get_boottime_seconds () - clp->cl_time);seq_printf (m,"name: " );seq_quote_mem (m, clp->cl_name.data, clp->cl_name.len);seq_printf (m,"\nminor version: %d\n" , clp->cl_minorversion);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 517/770 NFSD: Clean up nfsd3_proc_create()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit e61568599c9ad638fdaba150fee07d7065e31851 ]
As near as I can tell, mode bit masking and setting S_IFREG is already done by do_nfsd_create() and vfs_create(). The NFSv4 path (do_open_lookup), for example, does not bother with this special processing.
--- fs/nfsd/nfs3proc.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-)
fs/nfsd/nfs3proc.c +2 -14
@@ -229,8 +229,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp) {struct nfsd3_createargs *argp = rqstp->rq_argp;struct nfsd3_diropres *resp = rqstp->rq_resp; -svc_fh *dirfhp, *newfhp =NULL ; -struct iattr *attr; +svc_fh *dirfhp, *newfhp; dprintk("nfsd: CREATE(3) %s %.*s\n", SVCFH_fmt(&argp->fh),
@@ -239,20 +238,9 @@ nfsd3_proc_create(struct svc_rqst *rqstp) dirfhp =fh_copy (&resp->dirfh, &argp->fh); newfhp =fh_init (&resp->fh,NFS3_FHSIZE ); - attr = &argp->attrs; - -/* Unfudge the mode bits */ - attr->ia_mode &= ~S_IFMT ; -if (!(attr->ia_valid &ATTR_MODE )) { - attr->ia_valid |=ATTR_MODE ; - attr->ia_mode =S_IFREG ; - }else { - attr->ia_mode = (attr->ia_mode & ~S_IFMT ) |S_IFREG ; - } -/* Now create the file and set attributes */ resp->status =do_nfsd_create (rqstp, dirfhp, argp->name, argp->len, - attr, newfhp, argp->createmode, + &argp->attrs, newfhp, argp->createmode, (u32 *)argp->verf,NULL ,NULL );return rpc_success; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 518/770 NFSD: Avoid calling fh_drop_write() twice in do_nfsd_create()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 14ee45b70dd0d9ae76fb066cd8c0652d657353f6 ]
Clean up: The "out" label already invokes fh_drop_write().
Note that fh_drop_write() is already careful not to invoke mnt_drop_write() if either it has already been done or there is nothing to drop. Therefore no change in behavior is expected.
--- fs/nfsd/vfs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
fs/nfsd/vfs.c +1 -4
@@ -1504,7 +1504,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,case NFS3_CREATE_GUARDED : err = nfserr_exist; } -fh_drop_write (fhp); goto out; }
@@ -1512,10 +1511,8 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, iap->ia_mode &= ~current_umask (); host_err =vfs_create (dirp, dchild, iap->ia_mode, true); -if (host_err <0 ) { -fh_drop_write (fhp); +if (host_err <0 ) goto out_nfserr; - }if (created) *created = true;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 519/770 NFSD: Refactor nfsd_create_setattr()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 5f46e950c395b9c14c282b53ba78c5fd46d6c256 ]
I'd like to move do_nfsd_create() out of vfs.c. Therefore nfsd_create_setattr() needs to be made publicly visible.
Note that both call sites in vfs.c commit both the new object and its parent directory, so just combine those common metadata commits into nfsd_create_setattr().
--- fs/nfsd/vfs.c | 79 +++++++++++++++++++++++++++------------------------ fs/nfsd/vfs.h | 2 ++ 2 files changed, 44 insertions(+), 37 deletions(-)
fs/nfsd/vfs.c +42 -37
@@ -1207,14 +1207,26 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,return err; } -static __be32 -nfsd_create_setattr (struct svc_rqst *rqstp,struct svc_fh *resfhp, -struct iattr *iap) +/** +* nfsd_create_setattr - Set a created file's attributes +* @rqstp: RPC transaction being executed +* @fhp: NFS filehandle of parent directory +* @resfhp: NFS filehandle of new object +* @iap: requested attributes of new object +* +* Returns nfs_ok on success, or an nfsstat in network byte order. +*/ +__be32 +nfsd_create_setattr (struct svc_rqst *rqstp,struct svc_fh *fhp, +struct svc_fh *resfhp,struct iattr *iap) { +__be32 status; +/* -* Mode has already been set earlier in create: +* Mode has already been set by file creation. */ iap->ia_valid &= ~ATTR_MODE ; +/* * Setting uid/gid works only for root. Irix appears to * send along the gid on create when it tries to implement
@@ -1222,10 +1234,31 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,*/ if (!uid_eq (current_fsuid (),GLOBAL_ROOT_UID )) iap->ia_valid &= ~(ATTR_UID |ATTR_GID ); + +/* +* Callers expect new file metadata to be committed even +* if the attributes have not changed. +*/ if (iap->ia_valid) -return nfsd_setattr (rqstp, resfhp, iap,0 , (time64_t )0 ); -/* Callers expect file metadata to be committed here */ -return nfserrno (commit_metadata (resfhp)); + status =nfsd_setattr (rqstp, resfhp, iap,0 , (time64_t )0 ); +else + status =nfserrno (commit_metadata (resfhp)); + +/* +* Transactional filesystems had a chance to commit changes +* for both parent and child simultaneously making the +* following commit_metadata a noop in many cases. +*/ +if (!status) + status =nfserrno (commit_metadata (fhp)); + +/* +* Update the new filehandle to pick up the new attributes. +*/ +if (!status) + status =fh_update (resfhp); + +return status; }/* HPUX client sometimes creates a file in mode 000, and sets size to 0.
@@ -1252,7 +1285,6 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,struct dentry *dentry, *dchild;struct inode *dirp;__be32 err; -__be32 err2;int host_err; dentry = fhp->fh_dentry;
@@ -1324,22 +1356,8 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,if (host_err <0 ) goto out_nfserr; - err =nfsd_create_setattr (rqstp, resfhp, iap); + err =nfsd_create_setattr (rqstp, fhp, resfhp, iap); -/* -* nfsd_create_setattr already committed the child. Transactional -* filesystems had a chance to commit changes for both parent and -* child simultaneously making the following commit_metadata a -* noop. -*/ - err2 =nfserrno (commit_metadata (fhp)); -if (err2) - err = err2; -/* -* Update the file handle to get the new inode info. -*/ -if (!err) - err =fh_update (resfhp); out:dput (dchild);return err;
@@ -1530,20 +1548,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, } set_attr: - err =nfsd_create_setattr (rqstp, resfhp, iap); - -/* -* nfsd_create_setattr already committed the child -* (and possibly also the parent). -*/ -if (!err) - err =nfserrno (commit_metadata (fhp)); - -/* -* Update the filehandle to get the new inode info. -*/ -if (!err) - err =fh_update (resfhp); + err =nfsd_create_setattr (rqstp, fhp, resfhp, iap); out:fh_unlock (fhp);
fs/nfsd/vfs.h +2 -0
@@ -69,6 +69,8 @@ __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, int type, dev_t rdev, struct svc_fh *res);__be32 nfsd_access (struct svc_rqst *,struct svc_fh *,u32 *,u32 *); +__be32 nfsd_create_setattr (struct svc_rqst *rqstp,struct svc_fh *fhp, +struct svc_fh *resfhp,struct iattr *iap); __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, struct svc_fh *res, int createmode,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 520/770 NFSD: Refactor NFSv3 CREATE
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit df9606abddfb01090d5ece7dcc2441d848f690f0 ]
The NFSv3 CREATE and NFSv4 OPEN(CREATE) use cases are about to diverge such that it makes sense to split do_nfsd_create() into one version for NFSv3 and one for NFSv4.
As a first step, copy do_nfsd_create() to nfs3proc.c and remove NFSv4-specific logic.
One immediate legibility benefit is that the logic for handling NFSv3 createhow is now quite straightforward. NFSv4 createhow has some subtleties that IMO do not belong in generic code.
--- fs/nfsd/nfs3proc.c | 127 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 6 deletions(-)
fs/nfsd/nfs3proc.c +121 -6
@@ -8,6 +8,7 @@#include <linux/fs.h> #include <linux/ext2_fs.h> #include <linux/magic.h> +#include <linux/namei.h> #include "cache.h" #include "xdr3.h"
@@ -220,10 +221,126 @@ nfsd3_proc_write(struct svc_rqst *rqstp) }/* -* With NFSv3, CREATE processing is a lot easier than with NFSv2. -* At least in theory; we'll see how it fares in practice when the -* first reports about SunOS compatibility problems start to pour in... +* Implement NFSv3's unchecked, guarded, and exclusive CREATE +* semantics for regular files. Except for the created file, +* this operation is stateless on the server. +* +* Upon return, caller must release @fhp and @resfhp. */ +static __be32 +nfsd3_create_file (struct svc_rqst *rqstp,struct svc_fh *fhp, +struct svc_fh *resfhp,struct nfsd3_createargs *argp) +{ +struct iattr *iap = &argp->attrs; +struct dentry *parent, *child; +__u32 v_mtime, v_atime; +struct inode *inode; +__be32 status; +int host_err; + +if (isdotent (argp->name, argp->len)) +return nfserr_exist; +if (!(iap->ia_valid &ATTR_MODE )) + iap->ia_mode =0 ; + + status =fh_verify (rqstp, fhp,S_IFDIR ,NFSD_MAY_EXEC ); +if (status != nfs_ok) +return status; + + parent = fhp->fh_dentry; + inode =d_inode (parent); + + host_err =fh_want_write (fhp); +if (host_err) +return nfserrno (host_err); + +fh_lock_nested (fhp,I_MUTEX_PARENT ); + + child =lookup_one_len (argp->name, parent, argp->len); +if (IS_ERR (child)) { + status =nfserrno (PTR_ERR (child)); + goto out; + } + +if (d_really_is_negative (child)) { + status =fh_verify (rqstp, fhp,S_IFDIR ,NFSD_MAY_CREATE ); +if (status != nfs_ok) + goto out; + } + + status =fh_compose (resfhp, fhp->fh_export, child, fhp); +if (status != nfs_ok) + goto out; + + v_mtime =0 ; + v_atime =0 ; +if (argp->createmode ==NFS3_CREATE_EXCLUSIVE ) { +u32 *verifier = (u32 *)argp->verf; + +/* +* Solaris 7 gets confused (bugid 4218508) if these have +* the high bit set, as do xfs filesystems without the +* "bigtime" feature. So just clear the high bits. +*/ + v_mtime = verifier[0 ] &0x7fffffff ; + v_atime = verifier[1 ] &0x7fffffff ; + } + +if (d_really_is_positive (child)) { + status = nfs_ok; + +switch (argp->createmode) { +case NFS3_CREATE_UNCHECKED : +if (!d_is_reg (child)) +break ; + iap->ia_valid &=ATTR_SIZE ; + goto set_attr; +case NFS3_CREATE_GUARDED : + status = nfserr_exist; +break ; +case NFS3_CREATE_EXCLUSIVE : +if (d_inode (child)->i_mtime.tv_sec == v_mtime && +d_inode (child)->i_atime.tv_sec == v_atime && +d_inode (child)->i_size ==0 ) { +break ; + } + status = nfserr_exist; + } + goto out; + } + +if (!IS_POSIXACL (inode)) + iap->ia_mode &= ~current_umask (); + + host_err =vfs_create (inode, child, iap->ia_mode, true); +if (host_err <0 ) { + status =nfserrno (host_err); + goto out; + } + +/* A newly created file already has a file size of zero. */ +if ((iap->ia_valid &ATTR_SIZE ) && (iap->ia_size ==0 )) + iap->ia_valid &= ~ATTR_SIZE ; +if (argp->createmode ==NFS3_CREATE_EXCLUSIVE ) { + iap->ia_valid =ATTR_MTIME |ATTR_ATIME | +ATTR_MTIME_SET |ATTR_ATIME_SET ; + iap->ia_mtime.tv_sec = v_mtime; + iap->ia_atime.tv_sec = v_atime; + iap->ia_mtime.tv_nsec =0 ; + iap->ia_atime.tv_nsec =0 ; + } + +set_attr: + status =nfsd_create_setattr (rqstp, fhp, resfhp, iap); + +out: +fh_unlock (fhp); +if (child && !IS_ERR (child)) +dput (child); +fh_drop_write (fhp); +return status; +} +static __be32 nfsd3_proc_create (struct svc_rqst *rqstp) {
@@ -239,9 +356,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp) dirfhp =fh_copy (&resp->dirfh, &argp->fh); newfhp =fh_init (&resp->fh,NFS3_FHSIZE ); - resp->status =do_nfsd_create (rqstp, dirfhp, argp->name, argp->len, - &argp->attrs, newfhp, argp->createmode, - (u32 *)argp->verf,NULL ,NULL ); + resp->status =nfsd3_create_file (rqstp, dirfhp, newfhp, argp);return rpc_success; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 521/770 NFSD: Refactor NFSv4 OPEN(CREATE)
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 254454a5aa4a9f696d6bae080c08d5863e650f49 ]
Copy do_nfsd_create() to nfs4proc.c and remove NFSv3-specific logic.
--- fs/nfsd/nfs4proc.c | 162 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 152 insertions(+), 10 deletions(-)
fs/nfsd/nfs4proc.c +152 -10
@@ -37,6 +37,8 @@#include <linux/falloc.h> #include <linux/slab.h> #include <linux/kthread.h> +#include <linux/namei.h> +#include <linux/sunrpc/addr.h> #include <linux/nfs_ssc.h>
@@ -235,6 +237,154 @@ static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate &resfh->fh_handle); } +static inline bool nfsd4_create_is_exclusive (int createmode) +{ +return createmode ==NFS4_CREATE_EXCLUSIVE || + createmode ==NFS4_CREATE_EXCLUSIVE4_1 ; +} + +/* +* Implement NFSv4's unchecked, guarded, and exclusive create +* semantics for regular files. Open state for this new file is +* subsequently fabricated in nfsd4_process_open2(). +* +* Upon return, caller must release @fhp and @resfhp. +*/ +static __be32 +nfsd4_create_file (struct svc_rqst *rqstp,struct svc_fh *fhp, +struct svc_fh *resfhp,struct nfsd4_open *open) +{ +struct iattr *iap = &open->op_iattr; +struct dentry *parent, *child; +__u32 v_mtime, v_atime; +struct inode *inode; +__be32 status; +int host_err; + +if (isdotent (open->op_fname, open->op_fnamelen)) +return nfserr_exist; +if (!(iap->ia_valid &ATTR_MODE )) + iap->ia_mode =0 ; + + status =fh_verify (rqstp, fhp,S_IFDIR ,NFSD_MAY_EXEC ); +if (status != nfs_ok) +return status; + parent = fhp->fh_dentry; + inode =d_inode (parent); + + host_err =fh_want_write (fhp); +if (host_err) +return nfserrno (host_err); + +fh_lock_nested (fhp,I_MUTEX_PARENT ); + + child =lookup_one_len (open->op_fname, parent, open->op_fnamelen); +if (IS_ERR (child)) { + status =nfserrno (PTR_ERR (child)); + goto out; + } + +if (d_really_is_negative (child)) { + status =fh_verify (rqstp, fhp,S_IFDIR ,NFSD_MAY_CREATE ); +if (status != nfs_ok) + goto out; + } + + status =fh_compose (resfhp, fhp->fh_export, child, fhp); +if (status != nfs_ok) + goto out; + + v_mtime =0 ; + v_atime =0 ; +if (nfsd4_create_is_exclusive (open->op_createmode)) { +u32 *verifier = (u32 *)open->op_verf.data; + +/* +* Solaris 7 gets confused (bugid 4218508) if these have +* the high bit set, as do xfs filesystems without the +* "bigtime" feature. So just clear the high bits. If this +* is ever changed to use different attrs for storing the +* verifier, then do_open_lookup() will also need to be +* fixed accordingly. +*/ + v_mtime = verifier[0 ] &0x7fffffff ; + v_atime = verifier[1 ] &0x7fffffff ; + } + +if (d_really_is_positive (child)) { + status = nfs_ok; + +switch (open->op_createmode) { +case NFS4_CREATE_UNCHECKED : +if (!d_is_reg (child)) +break ; + +/* +* In NFSv4, we don't want to truncate the file +* now. This would be wrong if the OPEN fails for +* some other reason. Furthermore, if the size is +* nonzero, we should ignore it according to spec! +*/ + open->op_truncate = (iap->ia_valid &ATTR_SIZE ) && + !iap->ia_size; +break ; +case NFS4_CREATE_GUARDED : + status = nfserr_exist; +break ; +case NFS4_CREATE_EXCLUSIVE : +if (d_inode (child)->i_mtime.tv_sec == v_mtime && +d_inode (child)->i_atime.tv_sec == v_atime && +d_inode (child)->i_size ==0 ) { + open->op_created = true; +break ;/* subtle */ + } + status = nfserr_exist; +break ; +case NFS4_CREATE_EXCLUSIVE4_1 : +if (d_inode (child)->i_mtime.tv_sec == v_mtime && +d_inode (child)->i_atime.tv_sec == v_atime && +d_inode (child)->i_size ==0 ) { + open->op_created = true; + goto set_attr;/* subtle */ + } + status = nfserr_exist; + } + goto out; + } + +if (!IS_POSIXACL (inode)) + iap->ia_mode &= ~current_umask (); + + host_err =vfs_create (inode, child, iap->ia_mode, true); +if (host_err <0 ) { + status =nfserrno (host_err); + goto out; + } + open->op_created = true; + +/* A newly created file already has a file size of zero. */ +if ((iap->ia_valid &ATTR_SIZE ) && (iap->ia_size ==0 )) + iap->ia_valid &= ~ATTR_SIZE ; +if (nfsd4_create_is_exclusive (open->op_createmode)) { + iap->ia_valid =ATTR_MTIME |ATTR_ATIME | +ATTR_MTIME_SET |ATTR_ATIME_SET ; + iap->ia_mtime.tv_sec = v_mtime; + iap->ia_atime.tv_sec = v_atime; + iap->ia_mtime.tv_nsec =0 ; + iap->ia_atime.tv_nsec =0 ; + } + +set_attr: + status =nfsd_create_setattr (rqstp, fhp, resfhp, iap); + +out: +fh_unlock (fhp); +if (child && !IS_ERR (child)) +dput (child); +fh_drop_write (fhp); +return status; +} +static __be32 do_open_lookup (struct svc_rqst *rqstp,struct nfsd4_compound_state *cstate,struct nfsd4_open *open,struct svc_fh **resfh) {
@@ -264,16 +414,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru* yes | yes | GUARDED4 | GUARDED4 */ -/* -* Note: create modes (UNCHECKED,GUARDED...) are the same -* in NFSv4 as in v3 except EXCLUSIVE4_1. -*/ current->fs->umask = open->op_umask; - status =do_nfsd_create (rqstp, current_fh, open->op_fname, - open->op_fnamelen, &open->op_iattr, - *resfh, open->op_createmode, - (u32 *)open->op_verf.data, - &open->op_truncate, &open->op_created); + status =nfsd4_create_file (rqstp, current_fh, *resfh, open); current->fs->umask =0 ;if (!status && open->op_label.len)
@@ -284,7 +426,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru* use the returned bitmask to indicate which attributes * we used to store the verifier: */ -if (nfsd_create_is_exclusive (open->op_createmode) && status ==0 ) +if (nfsd4_create_is_exclusive (open->op_createmode) && status ==0 ) open->op_bmval[1 ] |= (FATTR4_WORD1_TIME_ACCESS |FATTR4_WORD1_TIME_MODIFY ); }else
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 522/770 NFSD: Remove do_nfsd_create()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 1c388f27759c5d9271d4fca081f7ee138986eb7d ]
Now that its two callers have their own version-specific instance of this function, do_nfsd_create() is no longer used.
--- fs/nfsd/vfs.c | 150 -------------------------------------------------- fs/nfsd/vfs.h | 10 ---- 2 files changed, 160 deletions(-)
fs/nfsd/vfs.c +0 -150
@@ -1412,156 +1412,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, rdev, resfhp); } -/* -* NFSv3 and NFSv4 version of nfsd_create -*/ -__be32 -do_nfsd_create (struct svc_rqst *rqstp,struct svc_fh *fhp, -char *fname,int flen,struct iattr *iap, -struct svc_fh *resfhp,int createmode,u32 *verifier, -bool *truncp,bool *created) -{ -struct dentry *dentry, *dchild =NULL ; -struct inode *dirp; -__be32 err; -int host_err; -__u32 v_mtime=0 , v_atime=0 ; - - err = nfserr_perm; -if (!flen) - goto out; - err = nfserr_exist; -if (isdotent (fname, flen)) - goto out; -if (!(iap->ia_valid &ATTR_MODE )) - iap->ia_mode =0 ; - err =fh_verify (rqstp, fhp,S_IFDIR ,NFSD_MAY_EXEC ); -if (err) - goto out; - - dentry = fhp->fh_dentry; - dirp =d_inode (dentry); - - host_err =fh_want_write (fhp); -if (host_err) - goto out_nfserr; - -fh_lock_nested (fhp,I_MUTEX_PARENT ); - -/* -* Compose the response file handle. -*/ - dchild =lookup_one_len (fname, dentry, flen); - host_err =PTR_ERR (dchild); -if (IS_ERR (dchild)) - goto out_nfserr; - -/* If file doesn't exist, check for permissions to create one */ -if (d_really_is_negative (dchild)) { - err =fh_verify (rqstp, fhp,S_IFDIR ,NFSD_MAY_CREATE ); -if (err) - goto out; - } - - err =fh_compose (resfhp, fhp->fh_export, dchild, fhp); -if (err) - goto out; - -if (nfsd_create_is_exclusive (createmode)) { -/* solaris7 gets confused (bugid 4218508) if these have -* the high bit set, as do xfs filesystems without the -* "bigtime" feature. So just clear the high bits. If this is -* ever changed to use different attrs for storing the -* verifier, then do_open_lookup() will also need to be fixed -* accordingly. -*/ - v_mtime = verifier[0 ]&0x7fffffff ; - v_atime = verifier[1 ]&0x7fffffff ; - } - -if (d_really_is_positive (dchild)) { - err =0 ; - -switch (createmode) { -case NFS3_CREATE_UNCHECKED : -if (!d_is_reg (dchild)) - goto out; -else if (truncp) { -/* in nfsv4, we need to treat this case a little -* differently. we don't want to truncate the -* file now; this would be wrong if the OPEN -* fails for some other reason. furthermore, -* if the size is nonzero, we should ignore it -* according to spec! -*/ - *truncp = (iap->ia_valid &ATTR_SIZE ) && !iap->ia_size; - } -else { - iap->ia_valid &=ATTR_SIZE ; - goto set_attr; - } -break ; -case NFS3_CREATE_EXCLUSIVE : -if (d_inode (dchild)->i_mtime.tv_sec == v_mtime - &&d_inode (dchild)->i_atime.tv_sec == v_atime - &&d_inode (dchild)->i_size ==0 ) { -if (created) - *created = true; -break ; - } - fallthrough; -case NFS4_CREATE_EXCLUSIVE4_1 : -if (d_inode (dchild)->i_mtime.tv_sec == v_mtime - &&d_inode (dchild)->i_atime.tv_sec == v_atime - &&d_inode (dchild)->i_size ==0 ) { -if (created) - *created = true; - goto set_attr; - } - fallthrough; -case NFS3_CREATE_GUARDED : - err = nfserr_exist; - } - goto out; - } - -if (!IS_POSIXACL (dirp)) - iap->ia_mode &= ~current_umask (); - - host_err =vfs_create (dirp, dchild, iap->ia_mode, true); -if (host_err <0 ) - goto out_nfserr; -if (created) - *created = true; - -nfsd_check_ignore_resizing (iap); - -if (nfsd_create_is_exclusive (createmode)) { -/* Cram the verifier into atime/mtime */ - iap->ia_valid =ATTR_MTIME |ATTR_ATIME - |ATTR_MTIME_SET |ATTR_ATIME_SET ; -/* XXX someone who knows this better please fix it for nsec */ - iap->ia_mtime.tv_sec = v_mtime; - iap->ia_atime.tv_sec = v_atime; - iap->ia_mtime.tv_nsec =0 ; - iap->ia_atime.tv_nsec =0 ; - } - - set_attr: - err =nfsd_create_setattr (rqstp, fhp, resfhp, iap); - - out: -fh_unlock (fhp); -if (dchild && !IS_ERR (dchild)) -dput (dchild); -fh_drop_write (fhp); -return err; - - out_nfserr: - err =nfserrno (host_err); - goto out; -} -/* * Read a symlink. On entry, *lenp must contain the maximum path length that * fits into the buffer. On return, it contains the true length.
fs/nfsd/vfs.h +0 -10
@@ -71,10 +71,6 @@ __be32 nfsd_create(struct svc_rqst *, struct svc_fh *,__be32 nfsd_access (struct svc_rqst *,struct svc_fh *,u32 *,u32 *);__be32 nfsd_create_setattr (struct svc_rqst *rqstp,struct svc_fh *fhp,struct svc_fh *resfhp,struct iattr *iap); -__be32 do_nfsd_create (struct svc_rqst *,struct svc_fh *, -char *name,int len,struct iattr *attrs, -struct svc_fh *res,int createmode, -u32 *verifier,bool *truncp,bool *created);__be32 nfsd_commit (struct svc_rqst *rqst,struct svc_fh *fhp,u64 offset,u32 count,__be32 *verf);#ifdef CONFIG_NFSD_V4
@@ -161,10 +157,4 @@ static inline __be32 fh_getattr(const struct svc_fh *fh, struct kstat *stat) AT_STATX_SYNC_AS_STAT)); } -static inline int nfsd_create_is_exclusive (int createmode) -{ -return createmode ==NFS3_CREATE_EXCLUSIVE - || createmode ==NFS4_CREATE_EXCLUSIVE4_1 ; -} -#endif /* LINUX_NFSD_VFS_H */
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 523/770 NFSD: Clean up nfsd_open_verified()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit f4d84c52643ae1d63a8e73e2585464470e7944d1 ]
Its only caller always passes S_IFREG as the @type parameter. As an additional clean-up, add a kerneldoc comment.
--- fs/nfsd/filecache.c | 4 ++-- fs/nfsd/vfs.c | 15 ++++++++++++--- fs/nfsd/vfs.h | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-)
fs/nfsd/filecache.c +2 -2
@@ -996,8 +996,8 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, nf->nf_mark =nfsd_file_mark_find_or_create (nf);if (nf->nf_mark) - status =nfsd_open_verified (rqstp, fhp,S_IFREG , - may_flags, &nf->nf_file); + status =nfsd_open_verified (rqstp, fhp, may_flags, + &nf->nf_file);else status = nfserr_jukebox;/*
fs/nfsd/vfs.c +12 -3
@@ -852,14 +852,23 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,return err; } +/** +* nfsd_open_verified - Open a regular file for the filecache +* @rqstp: RPC request +* @fhp: NFS filehandle of the file to open +* @may_flags: internal permission flags +* @filp: OUT: open "struct file *" +* +* Returns an nfsstat value in network byte order. +*/ __be32 -nfsd_open_verified (struct svc_rqst *rqstp,struct svc_fh *fhp,umode_t type, -int may_flags,struct file **filp) +nfsd_open_verified (struct svc_rqst *rqstp,struct svc_fh *fhp,int may_flags, +struct file **filp) {__be32 err;validate_process_creds (); - err =__nfsd_open (rqstp, fhp, type, may_flags, filp); + err =__nfsd_open (rqstp, fhp,S_IFREG , may_flags, filp);validate_process_creds ();return err; }
fs/nfsd/vfs.h +1 -1
@@ -86,7 +86,7 @@ __be32 nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,int nfsd_open_break_lease (struct inode *,int );__be32 nfsd_open (struct svc_rqst *,struct svc_fh *,umode_t ,int ,struct file **); -__be32 nfsd_open_verified (struct svc_rqst *,struct svc_fh *,umode_t , +__be32 nfsd_open_verified (struct svc_rqst *,struct svc_fh *,int ,struct file **); __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 524/770 NFSD: Instantiate a struct file when creating a regular NFSv4 file
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit fb70bf124b051d4ded4ce57511dfec6d3ebf2b43 ]
There have been reports of races that cause NFSv4 OPEN(CREATE) to return an error even though the requested file was created. NFSv4 does not provide a status code for this case.
To mitigate some of these problems, reorganize the NFSv4 OPEN(CREATE) logic to allocate resources before the file is actually created, and open the new file while the parent directory is still locked.
Two new APIs are added:
+ Add an API that works like nfsd_file_acquire() but does not open the underlying file. The OPEN(CREATE) path can use this API when it already has an open file.
+ Add an API that is kin to dentry_open(). NFSD needs to create a file and grab an open "struct file *" atomically. The alloc_empty_file() has to be done before the inode create. If it fails (for example, because the NFS server has exceeded its max_files limit), we avoid creating the file and can still return an error to the NFS client.
--- fs/nfsd/filecache.c | 51 ++++++++++++++++++++++++++++++++++++++------- fs/nfsd/filecache.h | 2 ++ fs/nfsd/nfs4proc.c | 43 ++++++++++++++++++++++++++++++++++---- fs/nfsd/nfs4state.c | 16 +++++++++++--- fs/nfsd/xdr4.h | 1 + fs/open.c | 41 ++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 2 ++ 7 files changed, 142 insertions(+), 14 deletions(-)
fs/nfsd/filecache.c +44 -7
@@ -898,9 +898,9 @@ nfsd_file_is_cached(struct inode *inode)return ret; } -__be32 -nfsd_file_acquire (struct svc_rqst *rqstp,struct svc_fh *fhp, -unsigned int may_flags,struct nfsd_file **pnf) +static __be32 +nfsd_do_file_acquire (struct svc_rqst *rqstp,struct svc_fh *fhp, +unsigned int may_flags,struct nfsd_file **pnf,bool open) {__be32 status;struct net *net =SVC_NET (rqstp);
@@ -995,10 +995,13 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,nfsd_file_gc (); nf->nf_mark =nfsd_file_mark_find_or_create (nf); -if (nf->nf_mark) - status =nfsd_open_verified (rqstp, fhp, may_flags, - &nf->nf_file); -else +if (nf->nf_mark) { +if (open) + status =nfsd_open_verified (rqstp, fhp, may_flags, + &nf->nf_file); +else + status = nfs_ok; + }else status = nfserr_jukebox;/* * If construction failed, or we raced with a call to unlink()
@@ -1018,6 +1021,40 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; } +/** +* nfsd_file_acquire - Get a struct nfsd_file with an open file +* @rqstp: the RPC transaction being executed +* @fhp: the NFS filehandle of the file to be opened +* @may_flags: NFSD_MAY_ settings for the file +* @pnf: OUT: new or found "struct nfsd_file" object +* +* Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in +* network byte order is returned. +*/ +__be32 +nfsd_file_acquire (struct svc_rqst *rqstp,struct svc_fh *fhp, +unsigned int may_flags,struct nfsd_file **pnf) +{ +return nfsd_do_file_acquire (rqstp, fhp, may_flags, pnf, true); +} + +/** +* nfsd_file_create - Get a struct nfsd_file, do not open +* @rqstp: the RPC transaction being executed +* @fhp: the NFS filehandle of the file just created +* @may_flags: NFSD_MAY_ settings for the file +* @pnf: OUT: new or found "struct nfsd_file" object +* +* Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in +* network byte order is returned. +*/ +__be32 +nfsd_file_create (struct svc_rqst *rqstp,struct svc_fh *fhp, +unsigned int may_flags,struct nfsd_file **pnf) +{ +return nfsd_do_file_acquire (rqstp, fhp, may_flags, pnf, false); +} +/* * Note that fields may be added, removed or reordered in the future. Programs * scraping this file for info should test the labels to ensure they're
fs/nfsd/filecache.h +2 -0
@@ -59,5 +59,7 @@ void nfsd_file_close_inode_sync(struct inode *inode);bool nfsd_file_is_cached (struct inode *inode);__be32 nfsd_file_acquire (struct svc_rqst *rqstp,struct svc_fh *fhp,unsigned int may_flags,struct nfsd_file **nfp); +__be32 nfsd_file_create (struct svc_rqst *rqstp,struct svc_fh *fhp, +unsigned int may_flags,struct nfsd_file **nfp);int nfsd_file_cache_stats_open (struct inode *,struct file *);#endif /* _FS_NFSD_FILECACHE_H */
fs/nfsd/nfs4proc.c +39 -4
68 lines not on this page · raw message
fs/nfsd/nfs4state.c +13 -3
@@ -5110,9 +5110,19 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,if (!fp->fi_fds[oflag]) {spin_unlock (&fp->fi_lock); - status =nfsd_file_acquire (rqstp, cur_fh, access, &nf); -if (status) - goto out_put_access; + +if (!open->op_filp) { + status =nfsd_file_acquire (rqstp, cur_fh, access, &nf); +if (status != nfs_ok) + goto out_put_access; + }else { + status =nfsd_file_create (rqstp, cur_fh, access, &nf); +if (status != nfs_ok) + goto out_put_access; + nf->nf_file = open->op_filp; + open->op_filp =NULL ; + } +spin_lock (&fp->fi_lock);if (!fp->fi_fds[oflag]) { fp->fi_fds[oflag] = nf;
fs/nfsd/xdr4.h +1 -0
@@ -273,6 +273,7 @@ struct nfsd4_open {bool op_truncate;/* used during processing */ bool op_created;/* used during processing */ struct nfs4_openowner *op_openowner;/* used during processing */ +struct file *op_filp;/* used during processing */ struct nfs4_file *op_file;/* used during processing */ struct nfs4_ol_stateid *op_stp;/* used during processing */ struct nfs4_clnt_odstate *op_odstate;/* used during processing */
fs/open.c +41 -0
47 lines not on this page · raw message
include/linux/fs.h +2 -0
@@ -2618,6 +2618,8 @@ extern struct file *filp_open(const char *, int, umode_t);extern struct file *file_open_root (struct dentry *,struct vfsmount *,const char *,int ,umode_t );extern struct file *dentry_open (const struct path *,int ,const struct cred *); +extern struct file *dentry_create (const struct path *path,int flags, +umode_t mode,const struct cred *cred);extern struct file *open_with_fake_path (const struct path *,int ,struct inode *,const struct cred *);static inline struct file *file_clone_open (struct file *file)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 525/770 NFSD: Remove dprintk call sites from tail of nfsd4_open()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit f67a16b147045815b6aaafeef8663e5faeb6d569 ]
Clean up: These relics are not likely to benefit server administrators.
--- fs/nfsd/nfs4proc.c | 4 ---- 1 file changed, 4 deletions(-)
fs/nfsd/nfs4proc.c +0 -4
@@ -622,13 +622,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,break ;case NFS4_OPEN_CLAIM_DELEG_PREV_FH :case NFS4_OPEN_CLAIM_DELEGATE_PREV : -dprintk ("NFSD: unsupported OPEN claim type %d\n" , - open->op_claim_type); status = nfserr_notsupp; goto out;default : -dprintk ("NFSD: Invalid OPEN claim type %d\n" , - open->op_claim_type); status = nfserr_inval; goto out; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 526/770 NFSD: Fix whitespace
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 26320d7e317c37404c811603d50d811132aef78c ]
Clean up: Pull case arms back one tab stop to conform every other switch statement in fs/nfsd/nfs4proc.c.
--- fs/nfsd/nfs4proc.c | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-)
fs/nfsd/nfs4proc.c +25 -25
@@ -600,33 +600,33 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out;switch (open->op_claim_type) { -case NFS4_OPEN_CLAIM_DELEGATE_CUR : -case NFS4_OPEN_CLAIM_NULL : - status =do_open_lookup (rqstp, cstate, open, &resfh); -if (status) - goto out; -break ; -case NFS4_OPEN_CLAIM_PREVIOUS : - status =nfs4_check_open_reclaim (cstate->clp); -if (status) - goto out; - open->op_openowner->oo_flags |=NFS4_OO_CONFIRMED ; - reclaim = true; - fallthrough; -case NFS4_OPEN_CLAIM_FH : -case NFS4_OPEN_CLAIM_DELEG_CUR_FH : - status =do_open_fhandle (rqstp, cstate, open); -if (status) - goto out; - resfh = &cstate->current_fh; -break ; -case NFS4_OPEN_CLAIM_DELEG_PREV_FH : -case NFS4_OPEN_CLAIM_DELEGATE_PREV : - status = nfserr_notsupp; +case NFS4_OPEN_CLAIM_DELEGATE_CUR : +case NFS4_OPEN_CLAIM_NULL : + status =do_open_lookup (rqstp, cstate, open, &resfh); +if (status) goto out; -default : - status = nfserr_inval; +break ; +case NFS4_OPEN_CLAIM_PREVIOUS : + status =nfs4_check_open_reclaim (cstate->clp); +if (status) goto out; + open->op_openowner->oo_flags |=NFS4_OO_CONFIRMED ; + reclaim = true; + fallthrough; +case NFS4_OPEN_CLAIM_FH : +case NFS4_OPEN_CLAIM_DELEG_CUR_FH : + status =do_open_fhandle (rqstp, cstate, open); +if (status) + goto out; + resfh = &cstate->current_fh; +break ; +case NFS4_OPEN_CLAIM_DELEG_PREV_FH : +case NFS4_OPEN_CLAIM_DELEGATE_PREV : + status = nfserr_notsupp; + goto out; +default : + status = nfserr_inval; + goto out; }/* * nfsd4_process_open2() does the actual opening of the file. If
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 527/770 NFSD: Move documenting comment for nfsd4_process_open2()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 7e2ce0cc15a509b859199235a2bad9cece00f67a ]
Clean up nfsd4_open() by converting a large comment at the only call site for nfsd4_process_open2() to a kerneldoc comment in front of that function.
--- fs/nfsd/nfs4proc.c | 6 +----- fs/nfsd/nfs4state.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 5 deletions(-)
fs/nfsd/nfs4proc.c +1 -5
@@ -628,11 +628,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_inval; goto out; } -/* -* nfsd4_process_open2() does the actual opening of the file. If -* successful, it (1) truncates the file if open->op_truncate was -* set, (2) sets open->op_stateid, (3) sets open->op_delegation. -*/ + status =nfsd4_process_open2 (rqstp, resfh, open); WARN(status && open->op_created, "nfsd4_process_open2 failed to open newly-created file! status=%u\n",
fs/nfsd/nfs4state.c +12 -0
@@ -5465,6 +5465,18 @@ static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,*/ } +/** +* nfsd4_process_open2 - finish open processing +* @rqstp: the RPC transaction being executed +* @current_fh: NFSv4 COMPOUND's current filehandle +* @open: OPEN arguments +* +* If successful, (1) truncate the file if open->op_truncate was +* set, (2) set open->op_stateid, (3) set open->op_delegation. +* +* Returns %nfs_ok on success; otherwise an nfs4stat value in +* network byte order is returned. +*/ __be32 nfsd4_process_open2 (struct svc_rqst *rqstp,struct svc_fh *current_fh,struct nfsd4_open *open) {
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 528/770 NFSD: Trace filecache opens
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 0122e882119ddbd9efa6edfeeac3f5c704a7aeea ]
Instrument calls to nfsd_open_verified() to get a sense of the filecache hit rate.
--- fs/nfsd/filecache.c | 5 +++-- fs/nfsd/trace.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-)
fs/nfsd/filecache.c +3 -2
@@ -996,10 +996,11 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, nf->nf_mark =nfsd_file_mark_find_or_create (nf);if (nf->nf_mark) { -if (open) +if (open) { status =nfsd_open_verified (rqstp, fhp, may_flags, &nf->nf_file); -else +trace_nfsd_file_open (nf, status); + }else status = nfs_ok; }else status = nfserr_jukebox;
fs/nfsd/trace.h +28 -0
@@ -795,6 +795,34 @@ TRACE_EVENT(nfsd_file_acquire, __entry->nf_file, __entry->status) ); +TRACE_EVENT (nfsd_file_open, + TP_PROTO(struct nfsd_file *nf, __be32 status), +TP_ARGS (nf, status), +TP_STRUCT__entry ( + __field(unsigned int, nf_hashval) + __field(void *, nf_inode) /* cannot be dereferenced */ + __field(int, nf_ref) + __field(unsigned long, nf_flags) + __field(unsigned long, nf_may) + __field(void *, nf_file) /* cannot be dereferenced */ + ), +TP_fast_assign ( + __entry->nf_hashval = nf->nf_hashval; + __entry->nf_inode = nf->nf_inode; + __entry->nf_ref = refcount_read(&nf->nf_ref); + __entry->nf_flags = nf->nf_flags; + __entry->nf_may = nf->nf_may; + __entry->nf_file = nf->nf_file; + ), +TP_printk ("hash=0x%x inode=%p ref=%d flags=%s may=%s file=%p" , + __entry->nf_hashval, + __entry->nf_inode, + __entry->nf_ref, +show_nf_flags (__entry->nf_flags), +show_nfsd_may_flags (__entry->nf_may), + __entry->nf_file) +) + DECLARE_EVENT_CLASS(nfsd_file_search_class, TP_PROTO(struct inode *inode, unsigned int hash, int found), TP_ARGS(inode, hash, found),
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 529/770 NFSD: Clean up the show_nf_flags() macro
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit bb283ca18d1e67c82d22a329c96c9d6036a74790 ]
The flags are defined using C macros, so TRACE_DEFINE_ENUM is unnecessary.
--- fs/nfsd/trace.h | 6 ------ 1 file changed, 6 deletions(-)
fs/nfsd/trace.h +0 -6
@@ -703,12 +703,6 @@ DEFINE_CLID_EVENT(confirmed_r);/* * from fs/nfsd/filecache.h */ -TRACE_DEFINE_ENUM (NFSD_FILE_HASHED ); -TRACE_DEFINE_ENUM (NFSD_FILE_PENDING ); -TRACE_DEFINE_ENUM (NFSD_FILE_BREAK_READ ); -TRACE_DEFINE_ENUM (NFSD_FILE_BREAK_WRITE ); -TRACE_DEFINE_ENUM (NFSD_FILE_REFERENCED ); -#define show_nf_flags (val) \ __print_flags(val, "|", \ { 1 << NFSD_FILE_HASHED, "HASHED" }, \
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 530/770 SUNRPC: Use RMW bitops in single-threaded hot paths
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 28df0988815f63e2af5e6718193c9f68681ad7ff ]
I noticed CPU pipeline stalls while using perf.
Once an svc thread is scheduled and executing an RPC, no other processes will touch svc_rqst::rq_flags. Thus bus-locked atomics are not needed outside the svc thread scheduler.
--- fs/nfsd/nfs4proc.c | 7 ++++--- fs/nfsd/nfs4xdr.c | 2 +- net/sunrpc/auth_gss/svcauth_gss.c | 4 ++-- net/sunrpc/svc.c | 6 +++--- net/sunrpc/svc_xprt.c | 2 +- net/sunrpc/svcsock.c | 8 ++++---- net/sunrpc/xprtrdma/svc_rdma_transport.c | 2 +- 7 files changed, 16 insertions(+), 15 deletions(-)
fs/nfsd/nfs4proc.c +4 -3
@@ -970,7 +970,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,* the client wants us to do more in this compound: */ if (!nfsd4_last_compound_op (rqstp)) -clear_bit (RQ_SPLICE_OK , &rqstp->rq_flags); +__clear_bit (RQ_SPLICE_OK , &rqstp->rq_flags);/* check stateid */ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
@@ -2642,11 +2642,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) cstate->minorversion = args->minorversion;fh_init (current_fh,NFS4_FHSIZE );fh_init (save_fh,NFS4_FHSIZE ); +/* * Don't use the deferral mechanism for NFSv4; compounds make it * too hard to avoid non-idempotency problems. */ -clear_bit (RQ_USEDEFERRAL , &rqstp->rq_flags); +__clear_bit (RQ_USEDEFERRAL , &rqstp->rq_flags);/* * According to RFC3010, this takes precedence over all other errors.
@@ -2761,7 +2762,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) out: cstate->status = status;/* Reset deferral mechanism for RPC deferrals */ -set_bit (RQ_USEDEFERRAL , &rqstp->rq_flags); +__set_bit (RQ_USEDEFERRAL , &rqstp->rq_flags);return rpc_success; }
fs/nfsd/nfs4xdr.c +1 -1
@@ -2411,7 +2411,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) argp->rqstp->rq_cachetype = cachethis ?RC_REPLBUFF :RC_NOCACHE ;if (readcount >1 || max_reply >PAGE_SIZE - auth_slack) -clear_bit (RQ_SPLICE_OK , &argp->rqstp->rq_flags); +__clear_bit (RQ_SPLICE_OK , &argp->rqstp->rq_flags);return true; }
net/sunrpc/auth_gss/svcauth_gss.c +2 -2
@@ -898,7 +898,7 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g* rejecting the server-computed MIC in this somewhat rare case, * do not use splice with the GSS integrity service. */ -clear_bit (RQ_SPLICE_OK , &rqstp->rq_flags); +__clear_bit (RQ_SPLICE_OK , &rqstp->rq_flags);/* Did we already verify the signature on the original pass through? */ if (rqstp->rq_deferred)
@@ -970,7 +970,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gsint pad, remaining_len, offset;u32 rseqno; -clear_bit (RQ_SPLICE_OK , &rqstp->rq_flags); +__clear_bit (RQ_SPLICE_OK , &rqstp->rq_flags); priv_len =svc_getnl (&buf->head[0 ]);if (rqstp->rq_deferred) {
net/sunrpc/svc.c +3 -3
@@ -1276,10 +1276,10 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) goto err_short_len;/* Will be turned off by GSS integrity and privacy services */ -set_bit (RQ_SPLICE_OK , &rqstp->rq_flags); +__set_bit (RQ_SPLICE_OK , &rqstp->rq_flags);/* Will be turned off only when NFSv4 Sessions are used */ -set_bit (RQ_USEDEFERRAL , &rqstp->rq_flags); -clear_bit (RQ_DROPME , &rqstp->rq_flags); +__set_bit (RQ_USEDEFERRAL , &rqstp->rq_flags); +__clear_bit (RQ_DROPME , &rqstp->rq_flags);svc_putu32 (resv, rqstp->rq_xid);
net/sunrpc/svc_xprt.c +1 -1
@@ -1228,7 +1228,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)trace_svc_defer (rqstp);svc_xprt_get (rqstp->rq_xprt); dr->xprt = rqstp->rq_xprt; -set_bit (RQ_DROPME , &rqstp->rq_flags); +__set_bit (RQ_DROPME , &rqstp->rq_flags); dr->handle.revisit = svc_revisit;return &dr->handle;
net/sunrpc/svcsock.c +4 -4
@@ -309,9 +309,9 @@ static void svc_sock_setbufsize(struct svc_sock *svsk, unsigned int nreqs)static void svc_sock_secure_port (struct svc_rqst *rqstp) {if (svc_port_is_privileged (svc_addr (rqstp))) -set_bit (RQ_SECURE , &rqstp->rq_flags); +__set_bit (RQ_SECURE , &rqstp->rq_flags);else -clear_bit (RQ_SECURE , &rqstp->rq_flags); +__clear_bit (RQ_SECURE , &rqstp->rq_flags); }/*
@@ -1014,9 +1014,9 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) rqstp->rq_xprt_ctxt =NULL ; rqstp->rq_prot =IPPROTO_TCP ;if (test_bit (XPT_LOCAL , &svsk->sk_xprt.xpt_flags)) -set_bit (RQ_LOCAL , &rqstp->rq_flags); +__set_bit (RQ_LOCAL , &rqstp->rq_flags);else -clear_bit (RQ_LOCAL , &rqstp->rq_flags); +__clear_bit (RQ_LOCAL , &rqstp->rq_flags); p = (__be32 *)rqstp->rq_arg.head[0 ].iov_base; calldir = p[1 ];
net/sunrpc/xprtrdma/svc_rdma_transport.c +1 -1
@@ -606,7 +606,7 @@ static int svc_rdma_has_wspace(struct svc_xprt *xprt)static void svc_rdma_secure_port (struct svc_rqst *rqstp) { -set_bit (RQ_SECURE , &rqstp->rq_flags); +__set_bit (RQ_SECURE , &rqstp->rq_flags); }static void svc_rdma_kill_temp_xprt (struct svc_xprt *xprt)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 531/770 nfsd: Unregister the cld notifier when laundry_wq create failed
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Xiaoxu <[email protected]>
[ Upstream commit 62fdb65edb6c43306c774939001f3a00974832aa ]
If laundry_wq create failed, the cld notifier should be unregistered.
--- fs/nfsd/nfsctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/nfsd/nfsctl.c +3 -1
@@ -1543,12 +1543,14 @@ static int __init init_nfsd(void) goto out_free_filesystem; retval =register_cld_notifier ();if (retval) - goto out_free_all; + goto out_free_subsys; retval =nfsd4_create_laundry_wq ();if (retval) goto out_free_all;return 0 ; out_free_all: +unregister_cld_notifier (); +out_free_subsys:unregister_pernet_subsys (&nfsd_net_ops); out_free_filesystem:unregister_filesystem (&nfsd_fs_type);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 532/770 nfsd: Fix null-ptr-deref in nfsd_fill_super()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Xiaoxu <[email protected]>
[ Upstream commit 6f6f84aa215f7b6665ccbb937db50860f9ec2989 ]
KASAN report null-ptr-deref as follows:
BUG: KASAN: null-ptr-deref in nfsd_fill_super+0xc6/0xe0 [nfsd] Write of size 8 at addr 000000000000005d by task a.out/852 CPU: 7 PID: 852 Comm: a.out Not tainted 5.18.0-rc7-dirty #66 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1.fc33 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x34/0x44 kasan_report+0xab/0x120 ? nfsd_mkdir+0x71/0x1c0 [nfsd] ? nfsd_fill_super+0xc6/0xe0 [nfsd] nfsd_fill_super+0xc6/0xe0 [nfsd] ? nfsd_mkdir+0x1c0/0x1c0 [nfsd] get_tree_keyed+0x8e/0x100 vfs_get_tree+0x41/0xf0 __do_sys_fsconfig+0x590/0x670 ? fscontext_read+0x180/0x180 ? anon_inode_getfd+0x4f/0x70 do_syscall_64+0x35/0x80 entry_SYSCALL_64_after_hwframe+0x44/0xae
This can be reproduce by concurrent operations:
1. fsopen(nfsd)/fsconfig
2. insmod/rmmod nfsd
Since the nfsd file system is registered before than nfsd_net allocated, the caller may get the file_system_type and use the nfsd_net before it allocated, then null-ptr-deref occurred.
So init_nfsd() should call register_filesystem() last.
--- fs/nfsd/nfsctl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
fs/nfsd/nfsctl.c +7 -7
@@ -1535,25 +1535,25 @@ static int __init init_nfsd(void) retval =create_proc_exports_entry ();if (retval) goto out_free_lockd; - retval =register_filesystem (&nfsd_fs_type); -if (retval) - goto out_free_exports; retval =register_pernet_subsys (&nfsd_net_ops);if (retval <0 ) - goto out_free_filesystem; + goto out_free_exports; retval =register_cld_notifier ();if (retval) goto out_free_subsys; retval =nfsd4_create_laundry_wq (); +if (retval) + goto out_free_cld; + retval =register_filesystem (&nfsd_fs_type);if (retval) goto out_free_all;return 0 ; out_free_all: +nfsd4_destroy_laundry_wq (); +out_free_cld:unregister_cld_notifier (); out_free_subsys:unregister_pernet_subsys (&nfsd_net_ops); -out_free_filesystem: -unregister_filesystem (&nfsd_fs_type); out_free_exports:remove_proc_entry ("fs/nfs/exports" ,NULL );remove_proc_entry ("fs/nfs" ,NULL );
@@ -1571,6 +1571,7 @@ static int __init init_nfsd(void) static void __exit exit_nfsd(void) { +unregister_filesystem (&nfsd_fs_type);nfsd4_destroy_laundry_wq ();unregister_cld_notifier ();unregister_pernet_subsys (&nfsd_net_ops);
@@ -1581,7 +1582,6 @@ static void __exit exit_nfsd(void)nfsd_lockd_shutdown ();nfsd4_free_slabs ();nfsd4_exit_pnfs (); -unregister_filesystem (&nfsd_fs_type); }MODULE_AUTHOR ("Olaf Kirch <[email protected]>" );
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 533/770 nfsd: destroy percpu stats counters after reply cache shutdown
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Schroeder <[email protected]>
[ Upstream commit fd5e363eac77ef81542db77ddad0559fa0f9204e ]
Upon nfsd shutdown any pending DRC cache is freed. DRC cache use is tracked via a percpu counter. In the current code the percpu counter is destroyed before. If any pending cache is still present, percpu_counter_add is called with a percpu counter==NULL. This causes a kernel crash.
The solution is to destroy the percpu counter after the cache is freed.
--- fs/nfsd/nfscache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfscache.c +1 -1
@@ -206,7 +206,6 @@ void nfsd_reply_cache_shutdown(struct nfsd_net *nn)struct svc_cacherep *rp;unsigned int i; -nfsd_reply_cache_stats_destroy (nn);unregister_shrinker (&nn->nfsd_reply_cache_shrinker);for (i =0 ; i < nn->drc_hashsize; i++) {
@@ -217,6 +216,7 @@ void nfsd_reply_cache_shutdown(struct nfsd_net *nn) rp, nn); } } +nfsd_reply_cache_stats_destroy (nn);kvfree (nn->drc_hashtbl); nn->drc_hashtbl =NULL ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 534/770 NFSD: Modernize nfsd4_release_lockowner()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit bd8fdb6e545f950f4654a9a10d7e819ad48146e5 ]
Refactor: Use existing helpers that other lock operations use. This change removes several automatic variables, so re-organize the variable declarations for readability.
--- fs/nfsd/nfs4state.c | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-)
fs/nfsd/nfs4state.c +11 -25
@@ -7562,16 +7562,13 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, union nfsd4_op_u *u) {struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; +struct nfsd_net *nn =net_generic (SVC_NET (rqstp), nfsd_net_id);clientid_t *clid = &rlockowner->rl_clientid; -struct nfs4_stateowner *sop; -struct nfs4_lockowner *lo =NULL ;struct nfs4_ol_stateid *stp; -struct xdr_netobj *owner = &rlockowner->rl_owner; -unsigned int hashval =ownerstr_hashval (owner); -__be32 status; -struct nfsd_net *nn =net_generic (SVC_NET (rqstp), nfsd_net_id); +struct nfs4_lockowner *lo;struct nfs4_client *clp; -LIST_HEAD (reaplist); +LIST_HEAD (reaplist); +__be32 status;dprintk ("nfsd4_release_lockowner clientid: (%08x/%08x):\n" , clid->cl_boot, clid->cl_id);
@@ -7579,30 +7576,19 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, status =set_client (clid, cstate, nn);if (status)return status; - clp = cstate->clp; -/* Find the matching lock stateowner */ -spin_lock (&clp->cl_lock); -list_for_each_entry (sop, &clp->cl_ownerstr_hashtbl[hashval], - so_strhash) { -if (sop->so_is_open_owner || !same_owner_str (sop, owner)) -continue ; - -if (atomic_read (&sop->so_count) !=1 ) { -spin_unlock (&clp->cl_lock); -return nfserr_locks_held; - } - - lo =lockowner (sop); -nfs4_get_stateowner (sop); -break ; - } +spin_lock (&clp->cl_lock); + lo =find_lockowner_str_locked (clp, &rlockowner->rl_owner);if (!lo) {spin_unlock (&clp->cl_lock);return status; } - +if (atomic_read (&lo->lo_owner.so_count) !=2 ) { +spin_unlock (&clp->cl_lock); +nfs4_put_stateowner (&lo->lo_owner); +return nfserr_locks_held; + }unhash_lockowner_locked (lo);while (!list_empty (&lo->lo_owner.so_stateids)) { stp = list_first_entry(&lo->lo_owner.so_stateids,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 535/770 NFSD: Add documenting comment for nfsd4_release_lockowner()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 043862b09cc00273e35e6c3a6389957953a34207 ]
And return explicit nfserr values that match what is documented in the new comment / API contract.
--- fs/nfsd/nfs4state.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-)
fs/nfsd/nfs4state.c +20 -3
@@ -7556,6 +7556,23 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)return status; } +/** +* nfsd4_release_lockowner - process NFSv4.0 RELEASE_LOCKOWNER operations +* @rqstp: RPC transaction +* @cstate: NFSv4 COMPOUND state +* @u: RELEASE_LOCKOWNER arguments +* +* The lockowner's so_count is bumped when a lock record is added +* or when copying a conflicting lock. The latter case is brief, +* but can lead to fleeting false positives when looking for +* locks-in-use. +* +* Return values: +* %nfs_ok: lockowner released or not found +* %nfserr_locks_held: lockowner still in use +* %nfserr_stale_clientid: clientid no longer active +* %nfserr_expired: clientid not recognized +*/ __be32 nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
@@ -7582,7 +7599,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, lo =find_lockowner_str_locked (clp, &rlockowner->rl_owner);if (!lo) {spin_unlock (&clp->cl_lock); -return status; +return nfs_ok; }if (atomic_read (&lo->lo_owner.so_count) !=2 ) {spin_unlock (&clp->cl_lock);
@@ -7598,11 +7615,11 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,put_ol_stateid_locked (stp, &reaplist); }spin_unlock (&clp->cl_lock); +free_ol_stateid_reaplist (&reaplist);remove_blocked_locks (lo);nfs4_put_stateowner (&lo->lo_owner); - -return status; +return nfs_ok; } static inline struct nfs4_client_reclaim *
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 536/770 NFSD: nfsd_file_put() can sleep
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 08af54b3e5729bc1d56ad3190af811301bdc37a1 ]
Now that there are no more callers of nfsd_file_put() that might hold a spin lock, ensure the lockdep infrastructure can catch newly introduced calls to nfsd_file_put() made while a spinlock is held.
--- fs/nfsd/filecache.c | 2 ++ 1 file changed, 2 insertions(+)
fs/nfsd/filecache.c +2 -0
@@ -302,6 +302,8 @@ nfsd_file_put_noref(struct nfsd_file *nf)void nfsd_file_put (struct nfsd_file *nf) { +might_sleep (); +set_bit (NFSD_FILE_REFERENCED , &nf->nf_flags);if (test_bit (NFSD_FILE_HASHED , &nf->nf_flags) ==0 ) {nfsd_file_flush (nf);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 537/770 NFSD: Fix potential use-after-free in nfsd_file_put()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit b6c71c66b0ad8f2b59d9bc08c7a5079b110bec01 ]
nfsd_file_put_noref() can free @nf, so don't dereference @nf immediately upon return from nfsd_file_put_noref().
--- fs/nfsd/filecache.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
fs/nfsd/filecache.c +5 -4
@@ -308,11 +308,12 @@ nfsd_file_put(struct nfsd_file *nf)if (test_bit (NFSD_FILE_HASHED , &nf->nf_flags) ==0 ) {nfsd_file_flush (nf);nfsd_file_put_noref (nf); - }else { + }else if (nf->nf_file) {nfsd_file_put_noref (nf); -if (nf->nf_file) -nfsd_file_schedule_laundrette (); - } +nfsd_file_schedule_laundrette (); + }else +nfsd_file_put_noref (nf); +if (atomic_long_read (&nfsd_filecache_count) >=NFSD_FILE_LRU_LIMIT )nfsd_file_gc (); }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 538/770 SUNRPC: Optimize xdr_reserve_space()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 62ed448cc53b654036f7d7f3c99f299d79ad14c3 ]
Transitioning between encode buffers is quite infrequent. It happens about 1 time in 400 calls to xdr_reserve_space(), measured on NFSD with a typical build/test workload.
Force the compiler to remove that code from xdr_reserve_space(), which is a hot path on both the server and the client. This change reduces the size of xdr_reserve_space() from 10 cache lines to 2 when compiled with -Os.
--- include/linux/sunrpc/xdr.h | 16 +++++++++++++++- net/sunrpc/xdr.c | 17 ++++++++++------- 2 files changed, 25 insertions(+), 8 deletions(-)
include/linux/sunrpc/xdr.h +15 -1
@@ -242,7 +242,7 @@ extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf,extern __be32 *xdr_reserve_space (struct xdr_stream *xdr,size_t nbytes);extern int xdr_reserve_space_vec (struct xdr_stream *xdr,struct kvec *vec,size_t nbytes); -extern void xdr_commit_encode (struct xdr_stream *xdr); +extern void __xdr_commit_encode (struct xdr_stream *xdr);extern void xdr_truncate_encode (struct xdr_stream *xdr,size_t len);extern int xdr_restrict_buflen (struct xdr_stream *xdr,int newbuflen); extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
@@ -305,6 +305,20 @@ xdr_reset_scratch_buffer(struct xdr_stream *xdr)xdr_set_scratch_buffer (xdr,NULL ,0 ); } +/** +* xdr_commit_encode - Ensure all data is written to xdr->buf +* @xdr: pointer to xdr_stream +* +* Handle encoding across page boundaries by giving the caller a +* temporary location to write to, then later copying the data into +* place. __xdr_commit_encode() does that copying. +*/ +static inline void xdr_commit_encode (struct xdr_stream *xdr) +{ +if (unlikely (xdr->scratch.iov_len)) +__xdr_commit_encode (xdr); +} +/** * xdr_stream_remaining - Return the number of bytes remaining in the stream * @xdr: pointer to struct xdr_stream
net/sunrpc/xdr.c +10 -7
@@ -691,7 +691,7 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p,EXPORT_SYMBOL_GPL (xdr_init_encode);/** -* xdr_commit_encode - Ensure all data is written to buffer +* __xdr_commit_encode - Ensure all data is written to buffer * @xdr: pointer to xdr_stream * * We handle encoding across page boundaries by giving the caller a
@@ -703,22 +703,25 @@ EXPORT_SYMBOL_GPL(xdr_init_encode);* required at the end of encoding, or any other time when the xdr_buf * data might be read. */ -inline void xdr_commit_encode (struct xdr_stream *xdr) +void __xdr_commit_encode (struct xdr_stream *xdr) {int shift = xdr->scratch.iov_len;void *page; -if (shift ==0 ) -return ; page =page_address (*xdr->page_ptr);memcpy (xdr->scratch.iov_base, page, shift);memmove (page, page + shift, (void *)xdr->p - page);xdr_reset_scratch_buffer (xdr); } -EXPORT_SYMBOL_GPL (xdr_commit_encode); +EXPORT_SYMBOL_GPL (__xdr_commit_encode); -static __be32 *xdr_get_next_encode_buffer (struct xdr_stream *xdr, -size_t nbytes) +/* +* The buffer space to be reserved crosses the boundary between +* xdr->buf->head and xdr->buf->pages, or between two pages +* in xdr->buf->pages. +*/ +static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, +size_t nbytes) {__be32 *p;int space_left;
Signature · 1 line
2.43.0