aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWendy Cheng <wcheng@redhat.com>2008-01-17 11:10:12 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2008-04-25 13:00:10 -0400
commit4373ea84c84d8a96e99d3da99e813d3e36d1bd11 (patch)
tree956fb92c4501cf2ed0f21a8942dfc31d4621711f
parent9d91cdcc0cce3186742f38e7352459b2087fbb86 (diff)
lockd: unlock lockd locks associated with a given server ip
For high-availability NFS service, we generally need to be able to drop file locks held on the exported filesystem before moving clients to a new server. Currently the only way to do that is by shutting down lockd entirely, which is often undesireable (for example, if you want to continue exporting other filesystems). This patch allows the administrator to release all locks held by clients accessing the client through a given server ip address, by echoing that address to a new file, /proc/fs/nfsd/unlock_ip, as in: shell> echo 10.1.1.2 > /proc/fs/nfsd/unlock_ip The expected sequence of events can be: 1. Tear down the IP address 2. Unexport the path 3. Write IP to /proc/fs/nfsd/unlock_ip to unlock files 4. Signal peer to begin take-over. For now we only support IPv4 addresses and NFSv2/v3 (NFSv4 locks are not affected). Also, if unmounting the filesystem is required, we assume at step 3 that clients using the given server ip are the only clients holding locks on the given filesystem; otherwise, an additional patch is required to allow revoking all locks held by lockd on a given filesystem. Signed-off-by: S. Wendy Cheng <wcheng@redhat.com> Cc: Lon Hohberger <lhh@redhat.com> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> fs/lockd/svcsubs.c | 66 +++++++++++++++++++++++++++++++++++++++----- fs/nfsd/nfsctl.c | 65 +++++++++++++++++++++++++++++++++++++++++++ include/linux/lockd/lockd.h | 7 ++++ 3 files changed, 131 insertions(+), 7 deletions(-)
-rw-r--r--fs/lockd/svcsubs.c36
-rw-r--r--fs/nfsd/nfsctl.c33
-rw-r--r--include/linux/lockd/lockd.h7
3 files changed, 70 insertions, 6 deletions
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index dbbefbcd6712..1adcf93cb6e6 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -18,6 +18,8 @@
18#include <linux/lockd/lockd.h> 18#include <linux/lockd/lockd.h>
19#include <linux/lockd/share.h> 19#include <linux/lockd/share.h>
20#include <linux/lockd/sm_inter.h> 20#include <linux/lockd/sm_inter.h>
21#include <linux/module.h>
22#include <linux/mount.h>
21 23
22#define NLMDBG_FACILITY NLMDBG_SVCSUBS 24#define NLMDBG_FACILITY NLMDBG_SVCSUBS
23 25
@@ -230,7 +232,7 @@ nlm_file_inuse(struct nlm_file *file)
230 * Loop over all files in the file table. 232 * Loop over all files in the file table.
231 */ 233 */
232static int 234static int
233nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match) 235nlm_traverse_files(void *data, nlm_host_match_fn_t match)
234{ 236{
235 struct hlist_node *pos, *next; 237 struct hlist_node *pos, *next;
236 struct nlm_file *file; 238 struct nlm_file *file;
@@ -244,7 +246,7 @@ nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
244 246
245 /* Traverse locks, blocks and shares of this file 247 /* Traverse locks, blocks and shares of this file
246 * and update file->f_locks count */ 248 * and update file->f_locks count */
247 if (nlm_inspect_file(host, file, match)) 249 if (nlm_inspect_file(data, file, match))
248 ret = 1; 250 ret = 1;
249 251
250 mutex_lock(&nlm_file_mutex); 252 mutex_lock(&nlm_file_mutex);
@@ -303,21 +305,27 @@ nlm_release_file(struct nlm_file *file)
303 * Used by nlmsvc_invalidate_all 305 * Used by nlmsvc_invalidate_all
304 */ 306 */
305static int 307static int
306nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy) 308nlmsvc_mark_host(void *data, struct nlm_host *dummy)
307{ 309{
310 struct nlm_host *host = data;
311
308 host->h_inuse = 1; 312 host->h_inuse = 1;
309 return 0; 313 return 0;
310} 314}
311 315
312static int 316static int
313nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other) 317nlmsvc_same_host(void *data, struct nlm_host *other)
314{ 318{
319 struct nlm_host *host = data;
320
315 return host == other; 321 return host == other;
316} 322}
317 323
318static int 324static int
319nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy) 325nlmsvc_is_client(void *data, struct nlm_host *dummy)
320{ 326{
327 struct nlm_host *host = data;
328
321 if (host->h_server) { 329 if (host->h_server) {
322 /* we are destroying locks even though the client 330 /* we are destroying locks even though the client
323 * hasn't asked us too, so don't unmonitor the 331 * hasn't asked us too, so don't unmonitor the
@@ -370,3 +378,21 @@ nlmsvc_invalidate_all(void)
370 */ 378 */
371 nlm_traverse_files(NULL, nlmsvc_is_client); 379 nlm_traverse_files(NULL, nlmsvc_is_client);
372} 380}
381
382static int
383nlmsvc_match_ip(void *datap, struct nlm_host *host)
384{
385 __be32 *server_addr = datap;
386
387 return host->h_saddr.sin_addr.s_addr == *server_addr;
388}
389
390int
391nlmsvc_unlock_all_by_ip(__be32 server_addr)
392{
393 int ret;
394 ret = nlm_traverse_files(&server_addr, nlmsvc_match_ip);
395 return ret ? -EIO : 0;
396
397}
398EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 613bcb8171a5..7706f6c9ab8a 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -22,6 +22,7 @@
22#include <linux/seq_file.h> 22#include <linux/seq_file.h>
23#include <linux/pagemap.h> 23#include <linux/pagemap.h>
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/inet.h>
25#include <linux/string.h> 26#include <linux/string.h>
26#include <linux/smp_lock.h> 27#include <linux/smp_lock.h>
27#include <linux/ctype.h> 28#include <linux/ctype.h>
@@ -35,6 +36,7 @@
35#include <linux/nfsd/cache.h> 36#include <linux/nfsd/cache.h>
36#include <linux/nfsd/xdr.h> 37#include <linux/nfsd/xdr.h>
37#include <linux/nfsd/syscall.h> 38#include <linux/nfsd/syscall.h>
39#include <linux/lockd/lockd.h>
38 40
39#include <asm/uaccess.h> 41#include <asm/uaccess.h>
40#include <net/ipv6.h> 42#include <net/ipv6.h>
@@ -53,6 +55,7 @@ enum {
53 NFSD_Getfs, 55 NFSD_Getfs,
54 NFSD_List, 56 NFSD_List,
55 NFSD_Fh, 57 NFSD_Fh,
58 NFSD_FO_UnlockIP,
56 NFSD_Threads, 59 NFSD_Threads,
57 NFSD_Pool_Threads, 60 NFSD_Pool_Threads,
58 NFSD_Versions, 61 NFSD_Versions,
@@ -89,6 +92,8 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
89static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); 92static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
90#endif 93#endif
91 94
95static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size);
96
92static ssize_t (*write_op[])(struct file *, char *, size_t) = { 97static ssize_t (*write_op[])(struct file *, char *, size_t) = {
93 [NFSD_Svc] = write_svc, 98 [NFSD_Svc] = write_svc,
94 [NFSD_Add] = write_add, 99 [NFSD_Add] = write_add,
@@ -98,6 +103,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
98 [NFSD_Getfd] = write_getfd, 103 [NFSD_Getfd] = write_getfd,
99 [NFSD_Getfs] = write_getfs, 104 [NFSD_Getfs] = write_getfs,
100 [NFSD_Fh] = write_filehandle, 105 [NFSD_Fh] = write_filehandle,
106 [NFSD_FO_UnlockIP] = failover_unlock_ip,
101 [NFSD_Threads] = write_threads, 107 [NFSD_Threads] = write_threads,
102 [NFSD_Pool_Threads] = write_pool_threads, 108 [NFSD_Pool_Threads] = write_pool_threads,
103 [NFSD_Versions] = write_versions, 109 [NFSD_Versions] = write_versions,
@@ -298,6 +304,31 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
298 return err; 304 return err;
299} 305}
300 306
307static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
308{
309 __be32 server_ip;
310 char *fo_path, c;
311 int b1, b2, b3, b4;
312
313 /* sanity check */
314 if (size == 0)
315 return -EINVAL;
316
317 if (buf[size-1] != '\n')
318 return -EINVAL;
319
320 fo_path = buf;
321 if (qword_get(&buf, fo_path, size) < 0)
322 return -EINVAL;
323
324 /* get ipv4 address */
325 if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
326 return -EINVAL;
327 server_ip = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
328
329 return nlmsvc_unlock_all_by_ip(server_ip);
330}
331
301static ssize_t write_filehandle(struct file *file, char *buf, size_t size) 332static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
302{ 333{
303 /* request is: 334 /* request is:
@@ -700,6 +731,8 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
700 [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, 731 [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
701 [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, 732 [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
702 [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, 733 [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
734 [NFSD_FO_UnlockIP] = {"unlock_ip",
735 &transaction_ops, S_IWUSR|S_IRUSR},
703 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, 736 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
704 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, 737 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
705 [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, 738 [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 94649a8da014..bcb93fc1fce7 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -194,7 +194,7 @@ void nsm_release(struct nsm_handle *);
194 * This is used in garbage collection and resource reclaim 194 * This is used in garbage collection and resource reclaim
195 * A return value != 0 means destroy the lock/block/share 195 * A return value != 0 means destroy the lock/block/share
196 */ 196 */
197typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref); 197typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
198 198
199/* 199/*
200 * Server-side lock handling 200 * Server-side lock handling
@@ -220,6 +220,11 @@ void nlmsvc_mark_resources(void);
220void nlmsvc_free_host_resources(struct nlm_host *); 220void nlmsvc_free_host_resources(struct nlm_host *);
221void nlmsvc_invalidate_all(void); 221void nlmsvc_invalidate_all(void);
222 222
223/*
224 * Cluster failover support
225 */
226int nlmsvc_unlock_all_by_ip(__be32 server_addr);
227
223static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) 228static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
224{ 229{
225 return file->f_file->f_path.dentry->d_inode; 230 return file->f_file->f_path.dentry->d_inode;