Blame view
fs/lockd/svcsubs.c
9.93 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 |
/* * linux/fs/lockd/svcsubs.c * * Various support routines for the NLM server. * * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> */ |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 11 |
#include <linux/types.h> #include <linux/string.h> #include <linux/time.h> #include <linux/in.h> |
5a0e3ad6a include cleanup: ... |
12 |
#include <linux/slab.h> |
353ab6e97 [PATCH] sem2mutex... |
13 |
#include <linux/mutex.h> |
1da177e4c Linux-2.6.12-rc2 |
14 15 16 17 18 19 |
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/clnt.h> #include <linux/nfsd/nfsfh.h> #include <linux/nfsd/export.h> #include <linux/lockd/lockd.h> #include <linux/lockd/share.h> |
4373ea84c lockd: unlock loc... |
20 21 |
#include <linux/module.h> #include <linux/mount.h> |
1da177e4c Linux-2.6.12-rc2 |
22 23 24 25 26 27 28 |
#define NLMDBG_FACILITY NLMDBG_SVCSUBS /* * Global file hash table */ |
07ba80635 [PATCH] knfsd: ch... |
29 |
#define FILE_HASH_BITS 7 |
1da177e4c Linux-2.6.12-rc2 |
30 |
#define FILE_NRHASH (1<<FILE_HASH_BITS) |
07ba80635 [PATCH] knfsd: ch... |
31 |
static struct hlist_head nlm_files[FILE_NRHASH]; |
353ab6e97 [PATCH] sem2mutex... |
32 |
static DEFINE_MUTEX(nlm_file_mutex); |
1da177e4c Linux-2.6.12-rc2 |
33 |
|
0bbacc402 NFS,SUNRPC,NLM: f... |
34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#ifdef NFSD_DEBUG static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) { u32 *fhp = (u32*)f->data; /* print the first 32 bytes of the fh */ dprintk("lockd: %s (%08x %08x %08x %08x %08x %08x %08x %08x) ", msg, fhp[0], fhp[1], fhp[2], fhp[3], fhp[4], fhp[5], fhp[6], fhp[7]); } static inline void nlm_debug_print_file(char *msg, struct nlm_file *file) { |
225a719f7 [PATCH] struct pa... |
48 |
struct inode *inode = file->f_file->f_path.dentry->d_inode; |
0bbacc402 NFS,SUNRPC,NLM: f... |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
dprintk("lockd: %s %s/%ld ", msg, inode->i_sb->s_id, inode->i_ino); } #else static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) { return; } static inline void nlm_debug_print_file(char *msg, struct nlm_file *file) { return; } #endif |
1da177e4c Linux-2.6.12-rc2 |
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
static inline unsigned int file_hash(struct nfs_fh *f) { unsigned int tmp=0; int i; for (i=0; i<NFS2_FHSIZE;i++) tmp += f->data[i]; return tmp & (FILE_NRHASH - 1); } /* * Lookup file info. If it doesn't exist, create a file info struct * and open a (VFS) file for the given inode. * * FIXME: * Note that we open the file O_RDONLY even when creating write locks. * This is not quite right, but for now, we assume the client performs * the proper R/W checking. */ |
52921e02a [PATCH] lockd end... |
83 |
__be32 |
1da177e4c Linux-2.6.12-rc2 |
84 85 86 |
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, struct nfs_fh *f) { |
07ba80635 [PATCH] knfsd: ch... |
87 |
struct hlist_node *pos; |
1da177e4c Linux-2.6.12-rc2 |
88 89 |
struct nlm_file *file; unsigned int hash; |
52921e02a [PATCH] lockd end... |
90 |
__be32 nfserr; |
1da177e4c Linux-2.6.12-rc2 |
91 |
|
50431d94e lockd: minor log ... |
92 |
nlm_debug_print_fh("nlm_lookup_file", f); |
1da177e4c Linux-2.6.12-rc2 |
93 94 95 96 |
hash = file_hash(f); /* Lock file table */ |
353ab6e97 [PATCH] sem2mutex... |
97 |
mutex_lock(&nlm_file_mutex); |
1da177e4c Linux-2.6.12-rc2 |
98 |
|
07ba80635 [PATCH] knfsd: ch... |
99 |
hlist_for_each_entry(file, pos, &nlm_files[hash], f_list) |
1da177e4c Linux-2.6.12-rc2 |
100 101 |
if (!nfs_compare_fh(&file->f_handle, f)) goto found; |
0bbacc402 NFS,SUNRPC,NLM: f... |
102 |
nlm_debug_print_fh("creating file for", f); |
1da177e4c Linux-2.6.12-rc2 |
103 104 |
nfserr = nlm_lck_denied_nolocks; |
f8314dc60 [PATCH] fs: Conve... |
105 |
file = kzalloc(sizeof(*file), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
106 107 |
if (!file) goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
108 |
memcpy(&file->f_handle, f, sizeof(struct nfs_fh)); |
89e63ef60 [PATCH] Convert l... |
109 |
mutex_init(&file->f_mutex); |
07ba80635 [PATCH] knfsd: ch... |
110 |
INIT_HLIST_NODE(&file->f_list); |
68a2d76ce [PATCH] knfsd: lo... |
111 |
INIT_LIST_HEAD(&file->f_blocks); |
1da177e4c Linux-2.6.12-rc2 |
112 113 114 115 116 117 118 119 |
/* Open the file. Note that this must not sleep for too long, else * we would lock up lockd:-) So no NFS re-exports, folks. * * We have to make sure we have the right credential to open * the file. */ if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) { |
f0737a39a [PATCH] knfsd: mi... |
120 121 |
dprintk("lockd: open failed (error %d) ", nfserr); |
1da177e4c Linux-2.6.12-rc2 |
122 123 |
goto out_free; } |
07ba80635 [PATCH] knfsd: ch... |
124 |
hlist_add_head(&file->f_list, &nlm_files[hash]); |
1da177e4c Linux-2.6.12-rc2 |
125 126 127 128 129 130 131 132 133 |
found: dprintk("lockd: found file %p (count %d) ", file, file->f_count); *result = file; file->f_count++; nfserr = 0; out_unlock: |
353ab6e97 [PATCH] sem2mutex... |
134 |
mutex_unlock(&nlm_file_mutex); |
1da177e4c Linux-2.6.12-rc2 |
135 136 137 138 |
return nfserr; out_free: kfree(file); |
1da177e4c Linux-2.6.12-rc2 |
139 140 141 142 143 144 145 146 147 |
goto out_unlock; } /* * Delete a file after having released all locks, blocks and shares */ static inline void nlm_delete_file(struct nlm_file *file) { |
0bbacc402 NFS,SUNRPC,NLM: f... |
148 |
nlm_debug_print_file("closing file", file); |
07ba80635 [PATCH] knfsd: ch... |
149 150 151 152 153 154 155 |
if (!hlist_unhashed(&file->f_list)) { hlist_del(&file->f_list); nlmsvc_ops->fclose(file->f_file); kfree(file); } else { printk(KERN_WARNING "lockd: attempt to release unknown file! "); |
1da177e4c Linux-2.6.12-rc2 |
156 |
} |
1da177e4c Linux-2.6.12-rc2 |
157 158 159 160 161 162 163 |
} /* * Loop over all locks on the given file and perform the specified * action. */ static int |
f2af793db [PATCH] knfsd: lo... |
164 165 |
nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match) |
1da177e4c Linux-2.6.12-rc2 |
166 167 168 169 170 171 172 |
{ struct inode *inode = nlmsvc_file_inode(file); struct file_lock *fl; struct nlm_host *lockhost; again: file->f_locks = 0; |
763641d81 lockd: push lock_... |
173 |
lock_flocks(); /* protects i_flock list */ |
1da177e4c Linux-2.6.12-rc2 |
174 |
for (fl = inode->i_flock; fl; fl = fl->fl_next) { |
7117bf3df lockd: Remove FL_... |
175 |
if (fl->fl_lmops != &nlmsvc_lock_operations) |
1da177e4c Linux-2.6.12-rc2 |
176 177 178 179 |
continue; /* update current lock count */ file->f_locks++; |
f2af793db [PATCH] knfsd: lo... |
180 |
|
1da177e4c Linux-2.6.12-rc2 |
181 |
lockhost = (struct nlm_host *) fl->fl_owner; |
f2af793db [PATCH] knfsd: lo... |
182 |
if (match(lockhost, host)) { |
1da177e4c Linux-2.6.12-rc2 |
183 |
struct file_lock lock = *fl; |
763641d81 lockd: push lock_... |
184 |
unlock_flocks(); |
1da177e4c Linux-2.6.12-rc2 |
185 186 187 |
lock.fl_type = F_UNLCK; lock.fl_start = 0; lock.fl_end = OFFSET_MAX; |
1a8322b2b lockd: add code t... |
188 |
if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) { |
1da177e4c Linux-2.6.12-rc2 |
189 190 191 192 193 194 195 196 |
printk("lockd: unlock failure in %s:%d ", __FILE__, __LINE__); return 1; } goto again; } } |
763641d81 lockd: push lock_... |
197 |
unlock_flocks(); |
1da177e4c Linux-2.6.12-rc2 |
198 199 200 |
return 0; } |
17efa372c lockd: unlock loc... |
201 202 203 204 205 |
static int nlmsvc_always_match(void *dummy1, struct nlm_host *dummy2) { return 1; } |
1da177e4c Linux-2.6.12-rc2 |
206 |
/* |
f2af793db [PATCH] knfsd: lo... |
207 208 209 210 211 212 213 214 215 216 217 218 219 |
* Inspect a single file */ static inline int nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match) { nlmsvc_traverse_blocks(host, file, match); nlmsvc_traverse_shares(host, file, match); return nlm_traverse_locks(host, file, match); } /* * Quick check whether there are still any locks, blocks or * shares on a given file. |
1da177e4c Linux-2.6.12-rc2 |
220 221 |
*/ static inline int |
f2af793db [PATCH] knfsd: lo... |
222 |
nlm_file_inuse(struct nlm_file *file) |
1da177e4c Linux-2.6.12-rc2 |
223 |
{ |
f2af793db [PATCH] knfsd: lo... |
224 225 226 227 228 |
struct inode *inode = nlmsvc_file_inode(file); struct file_lock *fl; if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares) return 1; |
763641d81 lockd: push lock_... |
229 |
lock_flocks(); |
f2af793db [PATCH] knfsd: lo... |
230 |
for (fl = inode->i_flock; fl; fl = fl->fl_next) { |
763641d81 lockd: push lock_... |
231 232 |
if (fl->fl_lmops == &nlmsvc_lock_operations) { unlock_flocks(); |
1da177e4c Linux-2.6.12-rc2 |
233 |
return 1; |
763641d81 lockd: push lock_... |
234 |
} |
1da177e4c Linux-2.6.12-rc2 |
235 |
} |
763641d81 lockd: push lock_... |
236 |
unlock_flocks(); |
f2af793db [PATCH] knfsd: lo... |
237 238 |
file->f_locks = 0; return 0; |
1da177e4c Linux-2.6.12-rc2 |
239 240 241 242 243 244 |
} /* * Loop over all files in the file table. */ static int |
17efa372c lockd: unlock loc... |
245 246 |
nlm_traverse_files(void *data, nlm_host_match_fn_t match, int (*is_failover_file)(void *data, struct nlm_file *file)) |
1da177e4c Linux-2.6.12-rc2 |
247 |
{ |
07ba80635 [PATCH] knfsd: ch... |
248 249 |
struct hlist_node *pos, *next; struct nlm_file *file; |
01df9c5e9 LOCKD: Fix a dead... |
250 |
int i, ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
251 |
|
353ab6e97 [PATCH] sem2mutex... |
252 |
mutex_lock(&nlm_file_mutex); |
1da177e4c Linux-2.6.12-rc2 |
253 |
for (i = 0; i < FILE_NRHASH; i++) { |
07ba80635 [PATCH] knfsd: ch... |
254 |
hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) { |
17efa372c lockd: unlock loc... |
255 256 |
if (is_failover_file && !is_failover_file(data, file)) continue; |
01df9c5e9 LOCKD: Fix a dead... |
257 258 |
file->f_count++; mutex_unlock(&nlm_file_mutex); |
1da177e4c Linux-2.6.12-rc2 |
259 260 |
/* Traverse locks, blocks and shares of this file * and update file->f_locks count */ |
4373ea84c lockd: unlock loc... |
261 |
if (nlm_inspect_file(data, file, match)) |
01df9c5e9 LOCKD: Fix a dead... |
262 |
ret = 1; |
1da177e4c Linux-2.6.12-rc2 |
263 |
|
01df9c5e9 LOCKD: Fix a dead... |
264 265 |
mutex_lock(&nlm_file_mutex); file->f_count--; |
1da177e4c Linux-2.6.12-rc2 |
266 |
/* No more references to this file. Let go of it. */ |
68a2d76ce [PATCH] knfsd: lo... |
267 |
if (list_empty(&file->f_blocks) && !file->f_locks |
1da177e4c Linux-2.6.12-rc2 |
268 |
&& !file->f_shares && !file->f_count) { |
07ba80635 [PATCH] knfsd: ch... |
269 |
hlist_del(&file->f_list); |
1da177e4c Linux-2.6.12-rc2 |
270 271 |
nlmsvc_ops->fclose(file->f_file); kfree(file); |
1da177e4c Linux-2.6.12-rc2 |
272 273 274 |
} } } |
353ab6e97 [PATCH] sem2mutex... |
275 |
mutex_unlock(&nlm_file_mutex); |
01df9c5e9 LOCKD: Fix a dead... |
276 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
} /* * Release file. If there are no more remote locks on this file, * close it and free the handle. * * Note that we can't do proper reference counting without major * contortions because the code in fs/locks.c creates, deletes and * splits locks without notification. Our only way is to walk the * entire lock list each time we remove a lock. */ void nlm_release_file(struct nlm_file *file) { dprintk("lockd: nlm_release_file(%p, ct = %d) ", file, file->f_count); /* Lock file table */ |
353ab6e97 [PATCH] sem2mutex... |
296 |
mutex_lock(&nlm_file_mutex); |
1da177e4c Linux-2.6.12-rc2 |
297 298 |
/* If there are no more locks etc, delete the file */ |
f2af793db [PATCH] knfsd: lo... |
299 300 |
if (--file->f_count == 0 && !nlm_file_inuse(file)) nlm_delete_file(file); |
1da177e4c Linux-2.6.12-rc2 |
301 |
|
353ab6e97 [PATCH] sem2mutex... |
302 |
mutex_unlock(&nlm_file_mutex); |
1da177e4c Linux-2.6.12-rc2 |
303 304 305 |
} /* |
f2af793db [PATCH] knfsd: lo... |
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
* Helpers function for resource traversal * * nlmsvc_mark_host: * used by the garbage collector; simply sets h_inuse. * Always returns 0. * * nlmsvc_same_host: * returns 1 iff the two hosts match. Used to release * all resources bound to a specific host. * * nlmsvc_is_client: * returns 1 iff the host is a client. * Used by nlmsvc_invalidate_all */ static int |
4373ea84c lockd: unlock loc... |
321 |
nlmsvc_mark_host(void *data, struct nlm_host *dummy) |
f2af793db [PATCH] knfsd: lo... |
322 |
{ |
4373ea84c lockd: unlock loc... |
323 |
struct nlm_host *host = data; |
f2af793db [PATCH] knfsd: lo... |
324 325 326 327 328 |
host->h_inuse = 1; return 0; } static int |
4373ea84c lockd: unlock loc... |
329 |
nlmsvc_same_host(void *data, struct nlm_host *other) |
f2af793db [PATCH] knfsd: lo... |
330 |
{ |
4373ea84c lockd: unlock loc... |
331 |
struct nlm_host *host = data; |
f2af793db [PATCH] knfsd: lo... |
332 333 334 335 |
return host == other; } static int |
4373ea84c lockd: unlock loc... |
336 |
nlmsvc_is_client(void *data, struct nlm_host *dummy) |
f2af793db [PATCH] knfsd: lo... |
337 |
{ |
4373ea84c lockd: unlock loc... |
338 |
struct nlm_host *host = data; |
4481d1038 [PATCH] knfsd: Fi... |
339 340 341 342 343 344 345 346 347 348 |
if (host->h_server) { /* we are destroying locks even though the client * hasn't asked us too, so don't unmonitor the * client */ if (host->h_nsmhandle) host->h_nsmhandle->sm_sticky = 1; return 1; } else return 0; |
f2af793db [PATCH] knfsd: lo... |
349 350 351 |
} /* |
1da177e4c Linux-2.6.12-rc2 |
352 353 354 355 356 357 358 |
* Mark all hosts that still hold resources */ void nlmsvc_mark_resources(void) { dprintk("lockd: nlmsvc_mark_resources "); |
17efa372c lockd: unlock loc... |
359 |
nlm_traverse_files(NULL, nlmsvc_mark_host, NULL); |
1da177e4c Linux-2.6.12-rc2 |
360 361 362 363 364 365 366 367 368 369 |
} /* * Release all resources held by the given client */ void nlmsvc_free_host_resources(struct nlm_host *host) { dprintk("lockd: nlmsvc_free_host_resources "); |
17efa372c lockd: unlock loc... |
370 |
if (nlm_traverse_files(host, nlmsvc_same_host, NULL)) { |
1da177e4c Linux-2.6.12-rc2 |
371 |
printk(KERN_WARNING |
f0737a39a [PATCH] knfsd: mi... |
372 373 |
"lockd: couldn't remove all locks held by %s ", |
1da177e4c Linux-2.6.12-rc2 |
374 |
host->h_name); |
f0737a39a [PATCH] knfsd: mi... |
375 376 |
BUG(); } |
1da177e4c Linux-2.6.12-rc2 |
377 |
} |
367c8c7bd lockd: Pass "stru... |
378 379 380 381 382 |
/** * nlmsvc_invalidate_all - remove all locks held for clients * * Release all locks held by NFS clients. * |
1da177e4c Linux-2.6.12-rc2 |
383 384 385 386 |
*/ void nlmsvc_invalidate_all(void) { |
367c8c7bd lockd: Pass "stru... |
387 |
/* |
f2af793db [PATCH] knfsd: lo... |
388 389 390 391 392 |
* Previously, the code would call * nlmsvc_free_host_resources for each client in * turn, which is about as inefficient as it gets. * Now we just do it once in nlm_traverse_files. */ |
17efa372c lockd: unlock loc... |
393 394 395 396 397 398 399 |
nlm_traverse_files(NULL, nlmsvc_is_client, NULL); } static int nlmsvc_match_sb(void *datap, struct nlm_file *file) { struct super_block *sb = datap; |
d8c9584ea vfs: prefer ->den... |
400 |
return sb == file->f_file->f_path.dentry->d_sb; |
17efa372c lockd: unlock loc... |
401 |
} |
367c8c7bd lockd: Pass "stru... |
402 403 404 405 406 407 |
/** * nlmsvc_unlock_all_by_sb - release locks held on this file system * @sb: super block * * Release all locks held by clients accessing this file system. */ |
17efa372c lockd: unlock loc... |
408 409 410 411 412 413 414 |
int nlmsvc_unlock_all_by_sb(struct super_block *sb) { int ret; ret = nlm_traverse_files(sb, nlmsvc_always_match, nlmsvc_match_sb); return ret ? -EIO : 0; |
1da177e4c Linux-2.6.12-rc2 |
415 |
} |
17efa372c lockd: unlock loc... |
416 |
EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb); |
4373ea84c lockd: unlock loc... |
417 418 419 420 |
static int nlmsvc_match_ip(void *datap, struct nlm_host *host) { |
4516fc045 sunrpc: add routi... |
421 |
return rpc_cmp_addr(nlm_srcaddr(host), datap); |
4373ea84c lockd: unlock loc... |
422 |
} |
367c8c7bd lockd: Pass "stru... |
423 424 425 426 427 428 429 |
/** * nlmsvc_unlock_all_by_ip - release local locks by IP address * @server_addr: server's IP address as seen by clients * * Release all locks held by clients accessing this host * via the passed in IP address. */ |
4373ea84c lockd: unlock loc... |
430 |
int |
367c8c7bd lockd: Pass "stru... |
431 |
nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr) |
4373ea84c lockd: unlock loc... |
432 433 |
{ int ret; |
4373ea84c lockd: unlock loc... |
434 |
|
367c8c7bd lockd: Pass "stru... |
435 436 |
ret = nlm_traverse_files(server_addr, nlmsvc_match_ip, NULL); return ret ? -EIO : 0; |
4373ea84c lockd: unlock loc... |
437 438 |
} EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip); |