diff options
author | Wendy Cheng <wcheng@redhat.com> | 2008-01-17 11:10:12 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2008-04-25 13:00:10 -0400 |
commit | 4373ea84c84d8a96e99d3da99e813d3e36d1bd11 (patch) | |
tree | 956fb92c4501cf2ed0f21a8942dfc31d4621711f | |
parent | 9d91cdcc0cce3186742f38e7352459b2087fbb86 (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.c | 36 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 33 | ||||
-rw-r--r-- | include/linux/lockd/lockd.h | 7 |
3 files changed, 70 insertions, 6 deletions
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index dbbefbcd671..1adcf93cb6e 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 | */ |
232 | static int | 234 | static int |
233 | nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match) | 235 | nlm_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 | */ |
305 | static int | 307 | static int |
306 | nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy) | 308 | nlmsvc_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 | ||
312 | static int | 316 | static int |
313 | nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other) | 317 | nlmsvc_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 | ||
318 | static int | 324 | static int |
319 | nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy) | 325 | nlmsvc_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 | |||
382 | static int | ||
383 | nlmsvc_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 | |||
390 | int | ||
391 | nlmsvc_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 | } | ||
398 | EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip); | ||
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 613bcb8171a..7706f6c9ab8 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); | |||
89 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | 92 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); |
90 | #endif | 93 | #endif |
91 | 94 | ||
95 | static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size); | ||
96 | |||
92 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { | 97 | static 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 | ||
307 | static 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 | |||
301 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size) | 332 | static 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 94649a8da01..bcb93fc1fce 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 | */ |
197 | typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref); | 197 | typedef 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); | |||
220 | void nlmsvc_free_host_resources(struct nlm_host *); | 220 | void nlmsvc_free_host_resources(struct nlm_host *); |
221 | void nlmsvc_invalidate_all(void); | 221 | void nlmsvc_invalidate_all(void); |
222 | 222 | ||
223 | /* | ||
224 | * Cluster failover support | ||
225 | */ | ||
226 | int nlmsvc_unlock_all_by_ip(__be32 server_addr); | ||
227 | |||
223 | static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) | 228 | static 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; |