NFS Force Unmounting
Subsystems (3)
v3 cover NFS Force Unmounting
After some additional testing on version 2, I realized that 1) my test setup was bad (Doh!) and 2) using remount isn't really an ideal method for setting the "serverfailed" mount flag. The reason being that any userspace remount is going to touch the file system and probably invoke some RPCs for inode validation as such. If the server is truly dead, these RPCs will have to time out before the flag could actually be set. This not only takes a long time, but will probably also fail, causing the remount to fail and not set the flag, defeating the purpose.
This patch set works around this by exposing the failed server flag in debugfs. In addition, the flag now applies at the nfs_client level (instead of the nfs_server). Setting the flag will cancel all RPCs in the client, as well as all nfs_servers attached to it. This ensures that you get all the mounts, even when dealing with submounts that cross remote device boundaries. This is also where the nosharecache option applying to nfs_clients becomes useful... it will prevent sharing between other explicit mount calls, but submounts will all still share a nfs_client (and fail together).
Obviously, debugfs is not a permanent solution for this, so some discussion needs to be had on how this will be administered "in the real world" (I think "remount" is off the table).
Joshua Watt (7):
SUNRPC: Add flag to kill new tasks
SUNRPC: Expose kill_new_tasks in debugfs
SUNRPC: Simplify client shutdown
NFS: Add debugfs for nfs_server and nfs_client
NFS: Propagate NFS_MOUNT_UNSHARED to clients
NFS: Add API to fail client
NFS: Control failed clients through debugfs
fs/nfs/Makefile | 2 +- fs/nfs/client.c | 121 ++++++++++++++++++++++++-- fs/nfs/debugfs.c | 202 ++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/inode.c | 5 ++ fs/nfs/internal.h | 11 +++ fs/nfs/nfs3client.c | 2 + fs/nfs/nfs4client.c | 5 ++ include/linux/nfs_fs_sb.h | 8 ++ include/linux/sunrpc/clnt.h | 1 + net/sunrpc/clnt.c | 12 +-- net/sunrpc/debugfs.c | 4 + net/sunrpc/sched.c | 3 + 12 files changed, 360 insertions(+), 16 deletions(-) create mode 100644 fs/nfs/debugfs.c
Signature · 1 line
2.13.6
RFC v3 1/7 SUNRPC: Add flag to kill new tasks
The flag causes any new tasks that are queued to exit immediately with -EIO instead of executing. This will allow clients (particularly NFS) to prevents these task from delaying shutdown of the RPC session longer than necessary.
--- include/linux/sunrpc/clnt.h | 1 + net/sunrpc/clnt.c | 4 +--- net/sunrpc/sched.c | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-)
include/linux/sunrpc/clnt.h +1 -0
@@ -54,6 +54,7 @@ struct rpc_clnt { cl_noretranstimeo: 1,/* No retransmit timeouts */ cl_autobind : 1,/* use getport() */ cl_chatty : 1;/* be verbose */ +bool cl_kill_new_tasks;/* Kill all new tasks */ struct rpc_rtt * cl_rtt;/* RTO estimator data */ const struct rpc_timeout *cl_timeout;/* Timeout strategy */
net/sunrpc/clnt.c +1 -3
@@ -626,6 +626,7 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args, new->cl_noretranstimeo = clnt->cl_noretranstimeo; new->cl_discrtry = clnt->cl_discrtry; new->cl_chatty = clnt->cl_chatty; + new->cl_kill_new_tasks = clnt->cl_kill_new_tasks;return new; out_err:
@@ -818,9 +819,6 @@ void rpc_killall_tasks(struct rpc_clnt *clnt) {struct rpc_task *rovr; - -if (list_empty (&clnt->cl_tasks)) -return ;dprintk ("RPC: killing all tasks for client %p\n" , clnt);/* * Spin lock all_tasks to prevent changes...
net/sunrpc/sched.c +3 -0
@@ -748,6 +748,9 @@ static void __rpc_execute(struct rpc_task *task)dprintk ("RPC: %5u __rpc_execute flags=0x%x\n" , task->tk_pid, task->tk_flags); +if (task->tk_client->cl_kill_new_tasks) +rpc_exit (task, -EIO ); +WARN_ON_ONCE (RPC_IS_QUEUED (task));if (RPC_IS_QUEUED (task))return ;
Signature · 1 line
2.13.6
RFC v3 2/7 SUNRPC: Expose kill_new_tasks in debugfs
In reply to Joshua Watt--- net/sunrpc/debugfs.c | 4 ++++ 1 file changed, 4 insertions(+)
net/sunrpc/debugfs.c +4 -0
@@ -160,6 +160,10 @@ rpc_clnt_debugfs_register(struct rpc_clnt *clnt)if (!debugfs_create_symlink ("xprt" , clnt->cl_debugfs, name)) goto out_err; +if (!debugfs_create_bool ("kill_new_tasks" ,S_IRUSR |S_IWUSR , + clnt->cl_debugfs, &clnt->cl_kill_new_tasks)) + goto out_err; +return ; out_err:debugfs_remove_recursive (clnt->cl_debugfs);
Signature · 1 line
2.13.6
RFC v3 3/7 SUNRPC: Simplify client shutdown
In reply to Joshua WattUse the flag to kill all new tasks when shutting down instead of repeatedly killing all the pending tasks.
--- net/sunrpc/clnt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
net/sunrpc/clnt.c +3 -5
@@ -851,11 +851,9 @@ void rpc_shutdown_client(struct rpc_clnt *clnt) clnt->cl_program->name, rcu_dereference(clnt->cl_xprt)->servername); -while (!list_empty (&clnt->cl_tasks)) { -rpc_killall_tasks (clnt); -wait_event_timeout (destroy_wait, -list_empty (&clnt->cl_tasks),1 *HZ ); - } + clnt->cl_kill_new_tasks = true; +rpc_killall_tasks (clnt); +wait_event (destroy_wait,list_empty (&clnt->cl_tasks));rpc_release_client (clnt); }
Signature · 1 line
2.13.6
RFC v3 4/7 NFS: Add debugfs for nfs_server and nfs_client
In reply to Joshua Watt--- fs/nfs/Makefile | 2 +- fs/nfs/client.c | 87 ++++++++++++++++++++++++++-- fs/nfs/debugfs.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/inode.c | 5 ++ fs/nfs/internal.h | 10 ++++ fs/nfs/nfs4client.c | 1 + include/linux/nfs_fs_sb.h | 5 ++ 7 files changed, 247 insertions(+), 6 deletions(-) create mode 100644 fs/nfs/debugfs.c
fs/nfs/Makefile +1 -1
@@ -6,7 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o CFLAGS_nfstrace.o += -I$(src) -nfs-y := client.o dir.o file.o getroot.o inode.o super.o \ +nfs-y := client.o debugfs.o dir.o file.o getroot.o inode.o super.o \ io.o direct.o pagelist.o read.o symlink.o unlink.o \ write.o namespace.o mount_clnt.o nfstrace.o export.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
fs/nfs/client.c +82 -5
164 lines not on this page · raw message
fs/nfs/debugfs.c new file +143 -0
143 lines not on this page · raw message
fs/nfs/inode.c +5 -0
@@ -2144,6 +2144,8 @@ static int __init init_nfs_fs(void)if (err) goto out0; +nfs_debugfs_init (); +return 0 ; out0:rpc_proc_unregister (&init_net,"nfs" );
@@ -2181,6 +2183,9 @@ static void __exit exit_nfs_fs(void)unregister_nfs_fs ();nfs_fs_proc_exit ();nfsiod_stop (); +nfs_cleanup_server_ids (); +nfs_cleanup_client_ids (); +nfs_debugfs_exit (); }/* Not quite true; I just maintain it */
fs/nfs/internal.h +10 -0
@@ -156,6 +156,7 @@ extern void nfs_umount(const struct nfs_mount_request *info);/* client.c */ extern const struct rpc_program nfs_program;extern void nfs_clients_init (struct net *net); +void nfs_cleanup_client_ids (void );extern struct nfs_client *nfs_alloc_client (const struct nfs_client_initdata *);int nfs_create_rpc_client (struct nfs_client *,const struct nfs_client_initdata *,rpc_authflavor_t );struct nfs_client *nfs_get_client (const struct nfs_client_initdata *);
@@ -165,6 +166,7 @@ void nfs_server_remove_lists(struct nfs_server *);void nfs_init_timeout_values (struct rpc_timeout *to,int proto,int timeo,int retrans);int nfs_init_server_rpcclient (struct nfs_server *,const struct rpc_timeout *t,rpc_authflavor_t ); +void nfs_cleanup_server_ids (void );struct nfs_server *nfs_alloc_server (void );void nfs_server_copy_userdata (struct nfs_server *,struct nfs_server *);
@@ -560,6 +562,14 @@ void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, struct nfs_direct_req *dreq);extern ssize_t nfs_dreq_bytes_left (struct nfs_direct_req *dreq); +/* debugfs.c */ +void nfs_server_debugfs_register (struct nfs_server *server); +void nfs_server_debugfs_unregister (struct nfs_server *server); +void nfs_client_debugfs_register (struct nfs_client *client); +void nfs_client_debugfs_unregister (struct nfs_client *client); +void __exit nfs_debugfs_exit(void); +void __init nfs_debugfs_init (void ); +/* nfs4proc.c */ extern struct nfs_client *nfs4_init_client (struct nfs_client *clp,const struct nfs_client_initdata *);
fs/nfs/nfs4client.c +1 -0
@@ -1086,6 +1086,7 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,if (error <0 ) goto error; +nfs_server_debugfs_register (server);return server; error:
include/linux/nfs_fs_sb.h +5 -0
@@ -27,6 +27,7 @@ struct nfs41_impl_id;struct nfs_client {atomic_t cl_count;atomic_t cl_mds_count; +unsigned int cl_id;/* client id */ int cl_cons_state;/* current construction state (-ve: init error) */ #define NFS_CS_READY 0/* ready to be used */ #define NFS_CS_INITING 1/* busy initialising */
@@ -120,6 +121,7 @@ struct nfs_client {#endif struct net *cl_net; +struct dentry *cl_debugfs;/* debugfs entry */ };/*
@@ -131,6 +133,7 @@ struct nfs_server {* that share the same client */ struct list_head master_link;/* link in master servers list */ +unsigned int id;/* server id */ struct rpc_clnt * client;/* RPC client handle */ struct rpc_clnt * client_acl;/* ACL RPC client handle */ struct nlm_host *nlm_host;/* NLM client handle */
@@ -225,6 +228,8 @@ struct nfs_server {unsigned short mountd_port;unsigned short mountd_protocol;struct rpc_wait_queue uoc_rpcwaitq; + +struct dentry *debugfs; };/* Server capabilities */
Signature · 1 line
2.13.6
RFC v3 5/7 NFS: Propagate NFS_MOUNT_UNSHARED to clients
In reply to Joshua WattPropagating the flag allows operations to be performed on the client without affecting other mounts to the same client, much like operations on the superblock will not affect other superblocks.
--- fs/nfs/client.c | 9 +++++++-- fs/nfs/nfs3client.c | 2 ++ fs/nfs/nfs4client.c | 4 ++++ include/linux/nfs_fs_sb.h | 1 + 4 files changed, 14 insertions(+), 2 deletions(-)
fs/nfs/client.c +7 -2
@@ -328,6 +328,10 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *datif (clp->cl_cons_state <0 )continue ; +/* Don't match clients that don't want to be shared */ +if (test_bit (NFS_CS_UNSHARED , &clp->cl_flags)) +continue ; +/* Different NFS versions cannot share the same nfs_client */ if (clp->rpc_ops != data->nfs_mod->rpc_ops)continue ;
@@ -428,7 +432,7 @@ init_client(struct nfs_client *new, const struct nfs_client_initdata *cl_init)*/ struct nfs_client *nfs_get_client (const struct nfs_client_initdata *cl_init) { -struct nfs_client *clp, *new =NULL ; +struct nfs_client *clp =NULL , *new =NULL ;struct nfs_net *nn =net_generic (cl_init->net, nfs_net_id);const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops;
@@ -441,7 +445,8 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) do { spin_lock(&nn->nfs_client_lock); - clp = nfs_match_client(cl_init); + if (!test_bit(NFS_CS_UNSHARED, &cl_init->init_flags)) + clp = nfs_match_client(cl_init); if (clp) { spin_unlock(&nn->nfs_client_lock); if (new)
fs/nfs/nfs3client.c +2 -0
@@ -102,6 +102,8 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,if (mds_srv->flags &NFS_MOUNT_NORESVPORT )set_bit (NFS_CS_NORESVPORT , &cl_init.init_flags); +if (mds_srv->flags &NFS_MOUNT_UNSHARED ) +__set_bit (NFS_CS_UNSHARED , &cl_init.init_flags);/* Use the MDS nfs_client cl_ipaddr. */ nfs_init_timeout_values (&ds_timeout, ds_proto, ds_timeo, ds_retrans);
fs/nfs/nfs4client.c +4 -0
@@ -852,6 +852,8 @@ static int nfs4_set_client(struct nfs_server *server,set_bit (NFS_CS_MIGRATION , &cl_init.init_flags);if (test_bit (NFS_MIG_TSM_POSSIBLE , &server->mig_status))set_bit (NFS_CS_TSM_POSSIBLE , &cl_init.init_flags); +if (server->flags &NFS_MOUNT_UNSHARED ) +__set_bit (NFS_CS_UNSHARED , &cl_init.init_flags);/* Allocate or find a client reference we can use */ clp =nfs_get_client (&cl_init);
@@ -910,6 +912,8 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,if (mds_srv->flags &NFS_MOUNT_NORESVPORT )__set_bit (NFS_CS_NORESVPORT , &cl_init.init_flags); +if (mds_srv->flags &NFS_MOUNT_UNSHARED ) +__set_bit (NFS_CS_UNSHARED , &cl_init.init_flags);/* * Set an authflavor equual to the MDS value. Use the MDS nfs_client
include/linux/nfs_fs_sb.h +1 -0
@@ -45,6 +45,7 @@ struct nfs_client {#define NFS_CS_INFINITE_SLOTS 3/* - don't limit TCP slots */ #define NFS_CS_NO_RETRANS_TIMEOUT 4/* - Disable retransmit timeouts */ #define NFS_CS_TSM_POSSIBLE 5/* - Maybe state migration */ +#define NFS_CS_UNSHARED 6/* - Client state not shared */ struct sockaddr_storage cl_addr;/* server identifier */ size_t cl_addrlen;char * cl_hostname;/* hostname of server */
Signature · 1 line
2.13.6
RFC v3 6/7 NFS: Add API to fail client
In reply to Joshua WattFailing a client will cause all current and future RPCs sent to it to fail with -EIO
--- fs/nfs/client.c | 25 +++++++++++++++++++++++++ fs/nfs/internal.h | 1 + include/linux/nfs_fs_sb.h | 2 ++ 3 files changed, 28 insertions(+)
fs/nfs/client.c +25 -0
@@ -758,6 +758,31 @@ static int nfs_init_server(struct nfs_server *server,return error; } +static void +fail_rpc_client (struct rpc_clnt *client,bool failed) +{ +if (IS_ERR (client)) +return ; + + client->cl_kill_new_tasks = failed; +if (failed) +rpc_killall_tasks (client); +} + +void +nfs_client_failed (struct nfs_client *client,bool failed) +{ +struct nfs_server *server; + + client->cl_failed = failed; +fail_rpc_client (client->cl_rpcclient, failed); + +list_for_each_entry_rcu (server, &client->cl_superblocks, client_link) { +fail_rpc_client (server->client, failed); +fail_rpc_client (server->client_acl, failed); + } +} +/* * Load up the server record from information gained in an fsinfo record */
fs/nfs/internal.h +1 -0
@@ -159,6 +159,7 @@ extern void nfs_clients_init(struct net *net);void nfs_cleanup_client_ids (void );extern struct nfs_client *nfs_alloc_client (const struct nfs_client_initdata *);int nfs_create_rpc_client (struct nfs_client *,const struct nfs_client_initdata *,rpc_authflavor_t ); +void nfs_client_failed (struct nfs_client *client,bool failed);struct nfs_client *nfs_get_client (const struct nfs_client_initdata *);int nfs_probe_fsinfo (struct nfs_server *server,struct nfs_fh *,struct nfs_fattr *);void nfs_server_insert_lists (struct nfs_server *);
include/linux/nfs_fs_sb.h +2 -0
@@ -58,6 +58,8 @@ struct nfs_client {int cl_proto;/* Network transport protocol */ struct nfs_subversion * cl_nfs_mod;/* pointer to nfs version module */ +bool cl_failed;/* Client has failed */ +u32 cl_minorversion;/* NFSv4 minorversion */ struct rpc_cred *cl_machine_cred;
Signature · 1 line
2.13.6
RFC v3 7/7 NFS: Control failed clients through debugfs
In reply to Joshua WattThe "failed" debugfs entry can be used to get or set the failed status of a nfs_client.
--- fs/nfs/debugfs.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+)
fs/nfs/debugfs.c +59 -0
@@ -80,6 +80,56 @@ nfs_server_debugfs_unregister(struct nfs_server *server) server->debugfs =NULL ; } +static int +client_failed_show (struct seq_file *f,void *private) +{ +struct nfs_client *client = f->private; + +seq_printf (f,"%c" , client->cl_failed ?'Y' :'N' ); +return 0 ; +} + +static ssize_t +client_failed_write (struct file *file,const char __user *user_buf, +size_t count,loff_t *ppos) +{ +struct seq_file *seq = file->private_data; +struct nfs_client *client = seq->private; +char buf[32 ]; +size_t buf_size; +bool failed; +int err; + + buf_size =min (count,sizeof (buf) -1 ); +if (copy_from_user (buf, user_buf, buf_size)) +return -EFAULT ; + + buf[buf_size] ='\0' ; + + err =strtobool (buf, &failed); +if (err) +return err; + +nfs_client_failed (client, failed); + +return count; +} + +static int +client_failed_open (struct inode *inode,struct file *file) +{ +return single_open (file, client_failed_show, inode->i_private); +} + +static const struct file_operations client_failed_fops = { + .owner =THIS_MODULE , + .open = client_failed_open, + .read = seq_read, + .write = client_failed_write, + .llseek = seq_lseek, + .release = single_release +}; +void nfs_client_debugfs_register (struct nfs_client *client) {
@@ -99,6 +149,15 @@ nfs_client_debugfs_register(struct nfs_client *client)link_rpc_client ("rpc_client" , client->cl_rpcclient, client->cl_debugfs); + +if (!debugfs_create_file ("failed" ,0600 , client->cl_debugfs, client, + &client_failed_fops)) + goto out_error; + +return ; +out_error: +debugfs_remove_recursive (client->cl_debugfs); + client->cl_debugfs =NULL ; }void
Signature · 1 line
2.13.6
T24gVHVlLCAyMDE3LTExLTE0IGF0IDE3OjA2IC0wNjAwLCBKb3NodWEgV2F0dCB3cm90ZToNCj4g QWZ0ZXIgc29tZSBhZGRpdGlvbmFsIHRlc3Rpbmcgb24gdmVyc2lvbiAyLCBJIHJlYWxpemVkIHRo YXQgMSkgbXkNCj4gdGVzdA0KPiBzZXR1cCB3YXMgYmFkIChEb2ghKSBhbmQgMikgdXNpbmcgcmVt b3VudCBpc24ndCByZWFsbHkgYW4gaWRlYWwNCj4gbWV0aG9kDQo+IGZvciBzZXR0aW5nIHRoZSAi c2VydmVyZmFpbGVkIiBtb3VudCBmbGFnLiBUaGUgcmVhc29uIGJlaW5nIHRoYXQgYW55DQo+IHVz ZXJzcGFjZSByZW1vdW50IGlzIGdvaW5nIHRvIHRvdWNoIHRoZSBmaWxlIHN5c3RlbSBhbmQgcHJv YmFibHkNCj4gaW52b2tlDQo+IHNvbWUgUlBDcyBmb3IgaW5vZGUgdmFsaWRhdGlvbiBhcyBzdWNo LiBJZiB0aGUgc2VydmVyIGlzIHRydWx5IGRlYWQsDQo+IHRoZXNlIFJQQ3Mgd2lsbCBoYXZlIHRv IHRpbWUgb3V0IGJlZm9yZSB0aGUgZmxhZyBjb3VsZCBhY3R1YWxseSBiZQ0KPiBzZXQuDQo+IFRo aXMgbm90IG9ubHkgdGFrZXMgYSBsb25nIHRpbWUsIGJ1dCB3aWxsIHByb2JhYmx5IGFsc28gZmFp bCwgY2F1c2luZw0KPiB0aGUgcmVtb3VudCB0byBmYWlsIGFuZCBub3Qgc2V0IHRoZSBmbGFnLCBk ZWZlYXRpbmcgdGhlIHB1cnBvc2UuDQoNCldoeT8gVGhlcmUgc2hvdWxkIGJlIG5vIHJlYXNvbiB0 byBoYXZlIHRvIHJldmFsaWRhdGUgdGhlIHBhdGggaW4gb3JkZXINCnRvIGNoYW5nZSBtb3VudCBv cHRpb25zIG9uIGEgbW91bnQgcG9pbnQuDQoNCj4gVGhpcyBwYXRjaCBzZXQgd29ya3MgYXJvdW5k IHRoaXMgYnkgZXhwb3NpbmcgdGhlIGZhaWxlZCBzZXJ2ZXIgZmxhZw0KPiBpbg0KPiBkZWJ1Z2Zz LiBJbiBhZGRpdGlvbiwgdGhlIGZsYWcgbm93IGFwcGxpZXMgYXQgdGhlIG5mc19jbGllbnQgbGV2 ZWwNCj4gKGluc3RlYWQgb2YgdGhlIG5mc19zZXJ2ZXIpLiBTZXR0aW5nIHRoZSBmbGFnIHdpbGwg Y2FuY2VsIGFsbCBSUENzIGluDQo+IHRoZSBjbGllbnQsIGFzIHdlbGwgYXMgYWxsIG5mc19zZXJ2 ZXJzIGF0dGFjaGVkIHRvIGl0LiBUaGlzIGVuc3VyZXMNCj4gdGhhdA0KPiB5b3UgZ2V0IGFsbCB0 aGUgbW91bnRzLCBldmVuIHdoZW4gZGVhbGluZyB3aXRoIHN1Ym1vdW50cyB0aGF0IGNyb3NzDQo+ IHJlbW90ZSBkZXZpY2UgYm91bmRhcmllcy4gVGhpcyBpcyBhbHNvIHdoZXJlIHRoZSBub3NoYXJl Y2FjaGUgb3B0aW9uDQo+IGFwcGx5aW5nIHRvIG5mc19jbGllbnRzIGJlY29tZXMgdXNlZnVsLi4u IGl0IHdpbGwgcHJldmVudCBzaGFyaW5nDQo+IGJldHdlZW4gb3RoZXIgZXhwbGljaXQgbW91bnQg Y2FsbHMsIGJ1dCBzdWJtb3VudHMgd2lsbCBhbGwgc3RpbGwNCj4gc2hhcmUgYQ0KPiBuZnNfY2xp ZW50IChhbmQgZmFpbCB0b2dldGhlcikuDQo+IA0KPiBPYnZpb3VzbHksIGRlYnVnZnMgaXMgbm90 IGEgcGVybWFuZW50IHNvbHV0aW9uIGZvciB0aGlzLCBzbyBzb21lDQo+IGRpc2N1c3Npb24gbmVl ZHMgdG8gYmUgaGFkIG9uIGhvdyB0aGlzIHdpbGwgYmUgYWRtaW5pc3RlcmVkICJpbiB0aGUNCj4g cmVhbA0KPiB3b3JsZCIgKEkgdGhpbmsgInJlbW91bnQiIGlzIG9mZiB0aGUgdGFibGUpLg0KPiAN Cg0KV2UncmUgbm90IGFkZGluZyBhbnkgQVBJcyB0byBkZWJ1Z2ZzLiBUaGF0J3MgYSBkZWFsIGJy ZWFrZXIuLi4NCg0KLS0gDQpUcm9uZCBNeWtsZWJ1c3QNCkxpbnV4IE5GUyBjbGllbnQgbWFpbnRh aW5lciwgUHJpbWFyeURhdGENCnRyb25kLm15a2xlYnVzdEBwcmltYXJ5ZGF0YS5jb20NCg==
Quoted 17 lines · Trond Myklebust
Quoted 7 lines · Joshua Watt
After some additional testing on version 2, I realized that 1) my test
setup was bad (Doh!) and 2) using remount isn't really an ideal method
for setting the "serverfailed" mount flag. The reason being that any
userspace remount is going to touch the file system and probablyQuoted 8 lines
invoke
some RPCs for inode validation as such. If the server is truly dead,
these RPCs will have to time out before the flag could actually be set.
This not only takes a long time, but will probably also fail, causing
the remount to fail and not set the flag, defeating the purpose.
Quoted 3 lines
Why? There should be no reason to have to revalidate the path in order
to change mount options on a mount point.
I figured this out... the revalidation is not required for the mount(2) syscall when remounting. However, libmount tries to do a few file system checks that do required validation. You can convince it to skip these checks like so:
mount -c 172.16.9.0:/ /tmp/nfsmount -o remount,serverfailed
The "-c" prevents canonicalizing the mount path (meaning you must provide the canonical path on the command line), and you have to specify the "block device" (e.g. "172.16.9.0:/") to prevent it doing some fstatat() checks on the mount path while parsing through mtab.
It's annoying you can't do the easier:
mount /tmp/nfsmount -o remount,serverfailed
but that's not the kernels fault.
Quoted 16 lines
Quoted 16 lines
This patch set works around this by exposing the failed server flag in
debugfs. In addition, the flag now applies at thenfs_clientlevel (instead of thenfs_server). Setting the flag will cancel all RPCs in
the client, as well as allnfs_serversattached to it. This ensures that
you get all the mounts, even when dealing with submounts that cross remote device boundaries. This is also where the nosharecache option
applying tonfs_clientsbecomes useful... it will prevent sharing between other explicit mount calls, but submounts will all still share anfs_client(and fail together).
Quoted 7 lines
Quoted 5 lines
Obviously, debugfs is not a permanent solution for this, so some discussion needs to be had on how this will be administered "in the real
world" (I think "remount" is off the table).We're not adding any APIs to debugfs. That's a deal breaker...
Sure. Is the mount option still the best way forward then, or are there other options to be explored?
Quoted 5 lines
Signature · 4 lines
-- Trond Myklebust Linux NFS client maintainer, PrimaryData [email protected]