Blame view
fs/lockd/clntproc.c
21 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 |
/* * linux/fs/lockd/clntproc.c * * RPC procedures for the client side NLM implementation * * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> */ |
1da177e4c Linux-2.6.12-rc2 |
8 |
#include <linux/module.h> |
5a0e3ad6a include cleanup: ... |
9 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
10 11 12 13 14 |
#include <linux/types.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/nfs_fs.h> #include <linux/utsname.h> |
7dfb71030 [PATCH] Add inclu... |
15 |
#include <linux/freezer.h> |
1da177e4c Linux-2.6.12-rc2 |
16 17 18 |
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/svc.h> #include <linux/lockd/lockd.h> |
1da177e4c Linux-2.6.12-rc2 |
19 20 21 |
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMCLNT_GRACE_WAIT (5*HZ) |
ecdbf769b [PATCH] NLM: fix ... |
22 |
#define NLMCLNT_POLL_TIMEOUT (30*HZ) |
aaaa99423 NLM: Ensure that ... |
23 |
#define NLMCLNT_MAX_RETRIES 3 |
1da177e4c Linux-2.6.12-rc2 |
24 25 26 27 |
static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *); |
e8c5c045d [PATCH] lockd end... |
28 |
static int nlm_stat_to_errno(__be32 stat); |
1da177e4c Linux-2.6.12-rc2 |
29 |
static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host); |
16fb24252 NLM: Fix argument... |
30 |
static int nlmclnt_cancel(struct nlm_host *, int , struct file_lock *); |
1da177e4c Linux-2.6.12-rc2 |
31 |
|
963d8fe53 RPC: Clean up RPC... |
32 33 |
static const struct rpc_call_ops nlmclnt_unlock_ops; static const struct rpc_call_ops nlmclnt_cancel_ops; |
1da177e4c Linux-2.6.12-rc2 |
34 35 36 |
/* * Cookie counter for NLM requests */ |
031d869d0 [PATCH] knfsd: ma... |
37 |
static atomic_t nlm_cookie = ATOMIC_INIT(0x1234); |
1da177e4c Linux-2.6.12-rc2 |
38 |
|
031d869d0 [PATCH] knfsd: ma... |
39 |
void nlmclnt_next_cookie(struct nlm_cookie *c) |
1da177e4c Linux-2.6.12-rc2 |
40 |
{ |
031d869d0 [PATCH] knfsd: ma... |
41 42 43 |
u32 cookie = atomic_inc_return(&nlm_cookie); memcpy(c->data, &cookie, 4); |
1da177e4c Linux-2.6.12-rc2 |
44 |
c->len=4; |
1da177e4c Linux-2.6.12-rc2 |
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
} static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner) { atomic_inc(&lockowner->count); return lockowner; } static void nlm_put_lockowner(struct nlm_lockowner *lockowner) { if (!atomic_dec_and_lock(&lockowner->count, &lockowner->host->h_lock)) return; list_del(&lockowner->list); spin_unlock(&lockowner->host->h_lock); |
8ea6ecc8b lockd: Create cli... |
59 |
nlmclnt_release_host(lockowner->host); |
1da177e4c Linux-2.6.12-rc2 |
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
kfree(lockowner); } static inline int nlm_pidbusy(struct nlm_host *host, uint32_t pid) { struct nlm_lockowner *lockowner; list_for_each_entry(lockowner, &host->h_lockowners, list) { if (lockowner->pid == pid) return -EBUSY; } return 0; } static inline uint32_t __nlm_alloc_pid(struct nlm_host *host) { uint32_t res; do { res = host->h_pidcount++; } while (nlm_pidbusy(host, res) < 0); return res; } static struct nlm_lockowner *__nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner) { struct nlm_lockowner *lockowner; list_for_each_entry(lockowner, &host->h_lockowners, list) { if (lockowner->owner != owner) continue; return nlm_get_lockowner(lockowner); } return NULL; } static struct nlm_lockowner *nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner) { struct nlm_lockowner *res, *new = NULL; spin_lock(&host->h_lock); res = __nlm_find_lockowner(host, owner); if (res == NULL) { spin_unlock(&host->h_lock); |
f52720ca5 [PATCH] fs: Remov... |
101 |
new = kmalloc(sizeof(*new), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
102 103 104 105 106 107 108 109 110 111 112 113 114 |
spin_lock(&host->h_lock); res = __nlm_find_lockowner(host, owner); if (res == NULL && new != NULL) { res = new; atomic_set(&new->count, 1); new->owner = owner; new->pid = __nlm_alloc_pid(host); new->host = nlm_get_host(host); list_add(&new->list, &host->h_lockowners); new = NULL; } } spin_unlock(&host->h_lock); |
f99d49adf [PATCH] kfree cle... |
115 |
kfree(new); |
1da177e4c Linux-2.6.12-rc2 |
116 117 118 119 120 121 122 123 124 125 126 127 |
return res; } /* * Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls */ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) { struct nlm_args *argp = &req->a_args; struct nlm_lock *lock = &argp->lock; nlmclnt_next_cookie(&argp->cookie); |
225a719f7 [PATCH] struct pa... |
128 |
memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh)); |
e9ff3990f [PATCH] namespace... |
129 |
lock->caller = utsname()->nodename; |
1da177e4c Linux-2.6.12-rc2 |
130 |
lock->oh.data = req->a_owner; |
7bab377fc lockd: Don't expo... |
131 132 |
lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", (unsigned int)fl->fl_u.nfs_fl.owner->pid, |
e9ff3990f [PATCH] namespace... |
133 |
utsname()->nodename); |
7bab377fc lockd: Don't expo... |
134 |
lock->svid = fl->fl_u.nfs_fl.owner->pid; |
3a649b884 NLM: Simplify cli... |
135 136 137 |
lock->fl.fl_start = fl->fl_start; lock->fl.fl_end = fl->fl_end; lock->fl.fl_type = fl->fl_type; |
1da177e4c Linux-2.6.12-rc2 |
138 139 140 141 |
} static void nlmclnt_release_lockargs(struct nlm_rqst *req) { |
3a649b884 NLM: Simplify cli... |
142 |
BUG_ON(req->a_args.lock.fl.fl_ops != NULL); |
1da177e4c Linux-2.6.12-rc2 |
143 |
} |
1093a60ef NLM/NFS: Use cach... |
144 145 146 147 148 149 |
/** * nlmclnt_proc - Perform a single client-side lock request * @host: address of a valid nlm_host context representing the NLM server * @cmd: fcntl-style file lock operation to perform * @fl: address of arguments for the lock operation * |
1da177e4c Linux-2.6.12-rc2 |
150 |
*/ |
1093a60ef NLM/NFS: Use cach... |
151 |
int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) |
1da177e4c Linux-2.6.12-rc2 |
152 |
{ |
92737230d NLM: Add nlmclnt_... |
153 |
struct nlm_rqst *call; |
1093a60ef NLM/NFS: Use cach... |
154 |
int status; |
1da177e4c Linux-2.6.12-rc2 |
155 |
|
1093a60ef NLM/NFS: Use cach... |
156 |
nlm_get_host(host); |
92737230d NLM: Add nlmclnt_... |
157 158 159 |
call = nlm_alloc_call(host); if (call == NULL) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
160 |
|
92737230d NLM: Add nlmclnt_... |
161 162 163 |
nlmclnt_locks_init_private(fl, host); /* Set up the argument struct */ nlmclnt_setlockargs(call, fl); |
1da177e4c Linux-2.6.12-rc2 |
164 |
|
1da177e4c Linux-2.6.12-rc2 |
165 166 167 168 169 170 171 172 173 174 |
if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { if (fl->fl_type != F_UNLCK) { call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; status = nlmclnt_lock(call, fl); } else status = nlmclnt_unlock(call, fl); } else if (IS_GETLK(cmd)) status = nlmclnt_test(call, fl); else status = -EINVAL; |
92737230d NLM: Add nlmclnt_... |
175 176 |
fl->fl_ops->fl_release_private(fl); fl->fl_ops = NULL; |
1da177e4c Linux-2.6.12-rc2 |
177 178 |
dprintk("lockd: clnt proc returns %d ", status); |
1da177e4c Linux-2.6.12-rc2 |
179 180 |
return status; } |
1093a60ef NLM/NFS: Use cach... |
181 |
EXPORT_SYMBOL_GPL(nlmclnt_proc); |
1da177e4c Linux-2.6.12-rc2 |
182 183 184 |
/* * Allocate an NLM RPC call struct |
92737230d NLM: Add nlmclnt_... |
185 186 187 |
* * Note: the caller must hold a reference to host. In case of failure, * this reference will be released. |
1da177e4c Linux-2.6.12-rc2 |
188 |
*/ |
92737230d NLM: Add nlmclnt_... |
189 |
struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) |
1da177e4c Linux-2.6.12-rc2 |
190 191 |
{ struct nlm_rqst *call; |
36943fa4b NLM: nlm_alloc_ca... |
192 193 194 |
for(;;) { call = kzalloc(sizeof(*call), GFP_KERNEL); if (call != NULL) { |
5e7f37a76 NLM/lockd: Add a ... |
195 |
atomic_set(&call->a_count, 1); |
1da177e4c Linux-2.6.12-rc2 |
196 197 |
locks_init_lock(&call->a_args.lock.fl); locks_init_lock(&call->a_res.lock.fl); |
92737230d NLM: Add nlmclnt_... |
198 |
call->a_host = host; |
1da177e4c Linux-2.6.12-rc2 |
199 200 |
return call; } |
36943fa4b NLM: nlm_alloc_ca... |
201 202 |
if (signalled()) break; |
92737230d NLM: Add nlmclnt_... |
203 204 |
printk("nlm_alloc_call: failed, waiting for memory "); |
041e0e3b1 [PATCH] fs: fix-u... |
205 |
schedule_timeout_interruptible(5*HZ); |
1da177e4c Linux-2.6.12-rc2 |
206 |
} |
8ea6ecc8b lockd: Create cli... |
207 |
nlmclnt_release_host(host); |
1da177e4c Linux-2.6.12-rc2 |
208 209 |
return NULL; } |
7db836d4a lockd: Split nlm_... |
210 |
void nlmclnt_release_call(struct nlm_rqst *call) |
92737230d NLM: Add nlmclnt_... |
211 |
{ |
5e7f37a76 NLM/lockd: Add a ... |
212 213 |
if (!atomic_dec_and_test(&call->a_count)) return; |
8ea6ecc8b lockd: Create cli... |
214 |
nlmclnt_release_host(call->a_host); |
92737230d NLM: Add nlmclnt_... |
215 216 217 218 219 220 |
nlmclnt_release_lockargs(call); kfree(call); } static void nlmclnt_rpc_release(void *data) { |
7db836d4a lockd: Split nlm_... |
221 |
nlmclnt_release_call(data); |
92737230d NLM: Add nlmclnt_... |
222 |
} |
1da177e4c Linux-2.6.12-rc2 |
223 224 225 226 227 228 229 230 |
static int nlm_wait_on_grace(wait_queue_head_t *queue) { DEFINE_WAIT(wait); int status = -EINTR; prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE); if (!signalled ()) { schedule_timeout(NLMCLNT_GRACE_WAIT); |
3e1d1d28d [PATCH] Cleanup p... |
231 |
try_to_freeze(); |
1da177e4c Linux-2.6.12-rc2 |
232 233 234 235 236 237 238 239 240 241 242 |
if (!signalled ()) status = 0; } finish_wait(queue, &wait); return status; } /* * Generic NLM call */ static int |
d11d10cc0 NLM/lockd: Ensure... |
243 |
nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc) |
1da177e4c Linux-2.6.12-rc2 |
244 245 246 247 248 249 250 251 |
{ struct nlm_host *host = req->a_host; struct rpc_clnt *clnt; struct nlm_args *argp = &req->a_args; struct nlm_res *resp = &req->a_res; struct rpc_message msg = { .rpc_argp = argp, .rpc_resp = resp, |
d11d10cc0 NLM/lockd: Ensure... |
252 |
.rpc_cred = cred, |
1da177e4c Linux-2.6.12-rc2 |
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
}; int status; dprintk("lockd: call procedure %d on %s ", (int)proc, host->h_name); do { if (host->h_reclaiming && !argp->reclaim) goto in_grace_period; /* If we have no RPC client yet, create one. */ if ((clnt = nlm_bind_host(host)) == NULL) return -ENOLCK; msg.rpc_proc = &clnt->cl_procinfo[proc]; /* Perform the RPC call. If an error occurs, try again */ if ((status = rpc_call_sync(clnt, &msg, 0)) < 0) { dprintk("lockd: rpc_call returned error %d ", -status); switch (status) { case -EPROTONOSUPPORT: status = -EINVAL; break; case -ECONNREFUSED: case -ETIMEDOUT: case -ENOTCONN: nlm_rebind_host(host); status = -EAGAIN; break; case -ERESTARTSYS: return signalled () ? -EINTR : status; default: break; } break; } else |
e8c5c045d [PATCH] lockd end... |
290 |
if (resp->status == nlm_lck_denied_grace_period) { |
1da177e4c Linux-2.6.12-rc2 |
291 292 293 294 295 296 297 298 299 300 301 302 303 |
dprintk("lockd: server in grace period "); if (argp->reclaim) { printk(KERN_WARNING "lockd: spurious grace period reject?! "); return -ENOLCK; } } else { if (!argp->reclaim) { /* We appear to be out of the grace period */ wake_up_all(&host->h_gracewait); } |
82c2c8b86 lockd: properly c... |
304 305 306 |
dprintk("lockd: server returns status %d ", ntohl(resp->status)); |
1da177e4c Linux-2.6.12-rc2 |
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
return 0; /* Okay, call complete */ } in_grace_period: /* * The server has rebooted and appears to be in the grace * period during which locks are only allowed to be * reclaimed. * We can only back off and try again later. */ status = nlm_wait_on_grace(&host->h_gracewait); } while (status == 0); return status; } /* * Generic NLM call, async version. */ |
dc9d8d048 NLM/lockd: conver... |
326 |
static struct rpc_task *__nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) |
1da177e4c Linux-2.6.12-rc2 |
327 328 329 |
{ struct nlm_host *host = req->a_host; struct rpc_clnt *clnt; |
dc9d8d048 NLM/lockd: conver... |
330 331 332 333 334 335 |
struct rpc_task_setup task_setup_data = { .rpc_message = msg, .callback_ops = tk_ops, .callback_data = req, .flags = RPC_TASK_ASYNC, }; |
1da177e4c Linux-2.6.12-rc2 |
336 337 338 339 340 341 |
dprintk("lockd: call procedure %d on %s (async) ", (int)proc, host->h_name); /* If we have no RPC client yet, create one. */ |
92737230d NLM: Add nlmclnt_... |
342 343 344 |
clnt = nlm_bind_host(host); if (clnt == NULL) goto out_err; |
d47166244 lockd: Add helper... |
345 |
msg->rpc_proc = &clnt->cl_procinfo[proc]; |
dc9d8d048 NLM/lockd: conver... |
346 |
task_setup_data.rpc_client = clnt; |
1da177e4c Linux-2.6.12-rc2 |
347 |
|
1da177e4c Linux-2.6.12-rc2 |
348 |
/* bootstrap and kick off the async RPC call */ |
dc9d8d048 NLM/lockd: conver... |
349 |
return rpc_run_task(&task_setup_data); |
92737230d NLM: Add nlmclnt_... |
350 |
out_err: |
a995e9eb3 NLM: Fix double f... |
351 |
tk_ops->rpc_release(req); |
dc9d8d048 NLM/lockd: conver... |
352 353 354 355 356 357 358 359 360 361 362 363 |
return ERR_PTR(-ENOLCK); } static int nlm_do_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) { struct rpc_task *task; task = __nlm_async_call(req, proc, msg, tk_ops); if (IS_ERR(task)) return PTR_ERR(task); rpc_put_task(task); return 0; |
1da177e4c Linux-2.6.12-rc2 |
364 |
} |
dc9d8d048 NLM/lockd: conver... |
365 366 367 |
/* * NLM asynchronous call. */ |
d47166244 lockd: Add helper... |
368 369 370 371 372 373 |
int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) { struct rpc_message msg = { .rpc_argp = &req->a_args, .rpc_resp = &req->a_res, }; |
dc9d8d048 NLM/lockd: conver... |
374 |
return nlm_do_async_call(req, proc, &msg, tk_ops); |
d47166244 lockd: Add helper... |
375 376 377 378 379 380 381 |
} int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) { struct rpc_message msg = { .rpc_argp = &req->a_res, }; |
dc9d8d048 NLM/lockd: conver... |
382 383 384 385 386 387 388 389 390 391 392 |
return nlm_do_async_call(req, proc, &msg, tk_ops); } /* * NLM client asynchronous call. * * Note that although the calls are asynchronous, and are therefore * guaranteed to complete, we still always attempt to wait for * completion in order to be able to correctly track the lock * state. */ |
d11d10cc0 NLM/lockd: Ensure... |
393 |
static int nlmclnt_async_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
dc9d8d048 NLM/lockd: conver... |
394 395 396 397 |
{ struct rpc_message msg = { .rpc_argp = &req->a_args, .rpc_resp = &req->a_res, |
d11d10cc0 NLM/lockd: Ensure... |
398 |
.rpc_cred = cred, |
dc9d8d048 NLM/lockd: conver... |
399 400 401 402 403 404 405 406 407 408 |
}; struct rpc_task *task; int err; task = __nlm_async_call(req, proc, &msg, tk_ops); if (IS_ERR(task)) return PTR_ERR(task); err = rpc_wait_for_completion_task(task); rpc_put_task(task); return err; |
d47166244 lockd: Add helper... |
409 |
} |
1da177e4c Linux-2.6.12-rc2 |
410 411 412 413 414 415 416 |
/* * TEST for the presence of a conflicting lock */ static int nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) { int status; |
d11d10cc0 NLM/lockd: Ensure... |
417 |
status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_TEST); |
1da177e4c Linux-2.6.12-rc2 |
418 |
if (status < 0) |
92737230d NLM: Add nlmclnt_... |
419 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
420 |
|
92737230d NLM: Add nlmclnt_... |
421 |
switch (req->a_res.status) { |
e8c5c045d [PATCH] lockd end... |
422 |
case nlm_granted: |
92737230d NLM: Add nlmclnt_... |
423 424 |
fl->fl_type = F_UNLCK; break; |
e8c5c045d [PATCH] lockd end... |
425 |
case nlm_lck_denied: |
92737230d NLM: Add nlmclnt_... |
426 427 428 429 |
/* * Report the conflicting lock back to the application. */ fl->fl_start = req->a_res.lock.fl.fl_start; |
d67d1c7bf nfs: set correct ... |
430 |
fl->fl_end = req->a_res.lock.fl.fl_end; |
92737230d NLM: Add nlmclnt_... |
431 432 433 434 435 |
fl->fl_type = req->a_res.lock.fl.fl_type; fl->fl_pid = 0; break; default: status = nlm_stat_to_errno(req->a_res.status); |
1da177e4c Linux-2.6.12-rc2 |
436 |
} |
92737230d NLM: Add nlmclnt_... |
437 |
out: |
7db836d4a lockd: Split nlm_... |
438 |
nlmclnt_release_call(req); |
92737230d NLM: Add nlmclnt_... |
439 |
return status; |
1da177e4c Linux-2.6.12-rc2 |
440 441 442 443 |
} static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl) { |
63185942c lockd: Remove BKL... |
444 |
spin_lock(&fl->fl_u.nfs_fl.owner->host->h_lock); |
4c060b531 lockd: Fix Oopses... |
445 446 447 |
new->fl_u.nfs_fl.state = fl->fl_u.nfs_fl.state; new->fl_u.nfs_fl.owner = nlm_get_lockowner(fl->fl_u.nfs_fl.owner); list_add_tail(&new->fl_u.nfs_fl.list, &fl->fl_u.nfs_fl.owner->host->h_granted); |
63185942c lockd: Remove BKL... |
448 |
spin_unlock(&fl->fl_u.nfs_fl.owner->host->h_lock); |
1da177e4c Linux-2.6.12-rc2 |
449 450 451 452 |
} static void nlmclnt_locks_release_private(struct file_lock *fl) { |
63185942c lockd: Remove BKL... |
453 |
spin_lock(&fl->fl_u.nfs_fl.owner->host->h_lock); |
4c060b531 lockd: Fix Oopses... |
454 |
list_del(&fl->fl_u.nfs_fl.list); |
63185942c lockd: Remove BKL... |
455 |
spin_unlock(&fl->fl_u.nfs_fl.owner->host->h_lock); |
1da177e4c Linux-2.6.12-rc2 |
456 |
nlm_put_lockowner(fl->fl_u.nfs_fl.owner); |
1da177e4c Linux-2.6.12-rc2 |
457 |
} |
6aed62853 const: make file_... |
458 |
static const struct file_lock_operations nlmclnt_lock_ops = { |
1da177e4c Linux-2.6.12-rc2 |
459 460 461 462 463 464 465 466 |
.fl_copy_lock = nlmclnt_locks_copy_lock, .fl_release_private = nlmclnt_locks_release_private, }; static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host) { BUG_ON(fl->fl_ops != NULL); fl->fl_u.nfs_fl.state = 0; |
1da177e4c Linux-2.6.12-rc2 |
467 |
fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner); |
4c060b531 lockd: Fix Oopses... |
468 |
INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list); |
1da177e4c Linux-2.6.12-rc2 |
469 470 |
fl->fl_ops = &nlmclnt_lock_ops; } |
9b0735749 NLM,NFSv4: Don't ... |
471 |
static int do_vfs_lock(struct file_lock *fl) |
1da177e4c Linux-2.6.12-rc2 |
472 473 474 475 476 477 478 479 480 481 482 483 |
{ int res = 0; switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { case FL_POSIX: res = posix_lock_file_wait(fl->fl_file, fl); break; case FL_FLOCK: res = flock_lock_file_wait(fl->fl_file, fl); break; default: BUG(); } |
9b0735749 NLM,NFSv4: Don't ... |
484 |
return res; |
1da177e4c Linux-2.6.12-rc2 |
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
} /* * LOCK: Try to create a lock * * Programmer Harassment Alert * * When given a blocking lock request in a sync RPC call, the HPUX lockd * will faithfully return LCK_BLOCKED but never cares to notify us when * the lock could be granted. This way, our local process could hang * around forever waiting for the callback. * * Solution A: Implement busy-waiting * Solution B: Use the async version of the call (NLM_LOCK_{MSG,RES}) * * For now I am implementing solution A, because I hate the idea of * re-implementing lockd for a third time in two months. The async * calls shouldn't be too hard to do, however. * * This is one of the lovely things about standards in the NFS area: * they're so soft and squishy you can't really blame HP for doing this. */ static int nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) { |
d11d10cc0 NLM/lockd: Ensure... |
510 |
struct rpc_cred *cred = nfs_file_cred(fl->fl_file); |
1da177e4c Linux-2.6.12-rc2 |
511 512 |
struct nlm_host *host = req->a_host; struct nlm_res *resp = &req->a_res; |
3a649b884 NLM: Simplify cli... |
513 |
struct nlm_wait *block = NULL; |
01c3b861c NLM,NFSv4: Wait o... |
514 |
unsigned char fl_flags = fl->fl_flags; |
5f50c0c6d NLM/lockd: Fix a ... |
515 |
unsigned char fl_type; |
3a649b884 NLM: Simplify cli... |
516 |
int status = -ENOLCK; |
1da177e4c Linux-2.6.12-rc2 |
517 |
|
501c1ed3f NLM: Remove redun... |
518 |
if (nsm_monitor(host) < 0) |
1da177e4c Linux-2.6.12-rc2 |
519 |
goto out; |
6c9dc4255 lockd: Update NSM... |
520 |
req->a_args.state = nsm_local_state; |
501c1ed3f NLM: Remove redun... |
521 |
|
01c3b861c NLM,NFSv4: Wait o... |
522 523 |
fl->fl_flags |= FL_ACCESS; status = do_vfs_lock(fl); |
4a9af59fe NLM/lockd: Ensure... |
524 |
fl->fl_flags = fl_flags; |
01c3b861c NLM,NFSv4: Wait o... |
525 526 |
if (status < 0) goto out; |
1da177e4c Linux-2.6.12-rc2 |
527 |
|
3a649b884 NLM: Simplify cli... |
528 |
block = nlmclnt_prepare_block(host, fl); |
28df955a2 NLM: Fix reclaim ... |
529 |
again: |
5f50c0c6d NLM/lockd: Fix a ... |
530 531 532 533 534 |
/* * Initialise resp->status to a valid non-zero value, * since 0 == nlm_lck_granted */ resp->status = nlm_lck_blocked; |
ecdbf769b [PATCH] NLM: fix ... |
535 |
for(;;) { |
28df955a2 NLM: Fix reclaim ... |
536 537 |
/* Reboot protection */ fl->fl_u.nfs_fl.state = host->h_state; |
d11d10cc0 NLM/lockd: Ensure... |
538 |
status = nlmclnt_call(cred, req, NLMPROC_LOCK); |
ecdbf769b [PATCH] NLM: fix ... |
539 |
if (status < 0) |
ecdbf769b [PATCH] NLM: fix ... |
540 |
break; |
ecdbf769b [PATCH] NLM: fix ... |
541 |
/* Did a reclaimer thread notify us of a server reboot? */ |
e8c5c045d [PATCH] lockd end... |
542 |
if (resp->status == nlm_lck_denied_grace_period) |
ecdbf769b [PATCH] NLM: fix ... |
543 |
continue; |
e8c5c045d [PATCH] lockd end... |
544 |
if (resp->status != nlm_lck_blocked) |
ecdbf769b [PATCH] NLM: fix ... |
545 |
break; |
3a649b884 NLM: Simplify cli... |
546 547 |
/* Wait on an NLM blocking lock */ status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); |
3a649b884 NLM: Simplify cli... |
548 |
if (status < 0) |
5f50c0c6d NLM/lockd: Fix a ... |
549 |
break; |
e8c5c045d [PATCH] lockd end... |
550 |
if (resp->status != nlm_lck_blocked) |
3a649b884 NLM: Simplify cli... |
551 |
break; |
ecdbf769b [PATCH] NLM: fix ... |
552 |
} |
1da177e4c Linux-2.6.12-rc2 |
553 |
|
5f50c0c6d NLM/lockd: Fix a ... |
554 555 556 557 558 559 560 561 562 |
/* if we were interrupted while blocking, then cancel the lock request * and exit */ if (resp->status == nlm_lck_blocked) { if (!req->a_args.block) goto out_unlock; if (nlmclnt_cancel(host, req->a_args.block, fl) == 0) goto out_unblock; } |
e8c5c045d [PATCH] lockd end... |
563 |
if (resp->status == nlm_granted) { |
28df955a2 NLM: Fix reclaim ... |
564 565 566 567 568 569 |
down_read(&host->h_rwsem); /* Check whether or not the server has rebooted */ if (fl->fl_u.nfs_fl.state != host->h_state) { up_read(&host->h_rwsem); goto again; } |
4c060b531 lockd: Fix Oopses... |
570 |
/* Ensure the resulting lock will get added to granted list */ |
4a9af59fe NLM/lockd: Ensure... |
571 |
fl->fl_flags |= FL_SLEEP; |
9b0735749 NLM,NFSv4: Don't ... |
572 |
if (do_vfs_lock(fl) < 0) |
8e24eea72 fs: replace remai... |
573 574 |
printk(KERN_WARNING "%s: VFS is out of sync with lock manager! ", __func__); |
28df955a2 NLM: Fix reclaim ... |
575 |
up_read(&host->h_rwsem); |
4a9af59fe NLM/lockd: Ensure... |
576 |
fl->fl_flags = fl_flags; |
5f50c0c6d NLM/lockd: Fix a ... |
577 |
status = 0; |
1da177e4c Linux-2.6.12-rc2 |
578 |
} |
5f50c0c6d NLM/lockd: Fix a ... |
579 580 |
if (status < 0) goto out_unlock; |
cc77b1521 lockd: dont retur... |
581 582 583 584 585 586 587 588 589 |
/* * EAGAIN doesn't make sense for sleeping locks, and in some * cases NLM_LCK_DENIED is returned for a permanent error. So * turn it into an ENOLCK. */ if (resp->status == nlm_lck_denied && (fl_flags & FL_SLEEP)) status = -ENOLCK; else status = nlm_stat_to_errno(resp->status); |
ecdbf769b [PATCH] NLM: fix ... |
590 |
out_unblock: |
3a649b884 NLM: Simplify cli... |
591 |
nlmclnt_finish_block(block); |
1da177e4c Linux-2.6.12-rc2 |
592 |
out: |
7db836d4a lockd: Split nlm_... |
593 |
nlmclnt_release_call(req); |
1da177e4c Linux-2.6.12-rc2 |
594 |
return status; |
5f50c0c6d NLM/lockd: Fix a ... |
595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
out_unlock: /* Fatal error: ensure that we remove the lock altogether */ dprintk("lockd: lock attempt ended in fatal error. " " Attempting to unlock. "); nlmclnt_finish_block(block); fl_type = fl->fl_type; fl->fl_type = F_UNLCK; down_read(&host->h_rwsem); do_vfs_lock(fl); up_read(&host->h_rwsem); fl->fl_type = fl_type; fl->fl_flags = fl_flags; |
d11d10cc0 NLM/lockd: Ensure... |
609 |
nlmclnt_async_call(cred, req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); |
5f50c0c6d NLM/lockd: Fix a ... |
610 |
return status; |
1da177e4c Linux-2.6.12-rc2 |
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 |
} /* * RECLAIM: Try to reclaim a lock */ int nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl) { struct nlm_rqst reqst, *req; int status; req = &reqst; memset(req, 0, sizeof(*req)); locks_init_lock(&req->a_args.lock.fl); locks_init_lock(&req->a_res.lock.fl); req->a_host = host; req->a_flags = 0; /* Set up the argument struct */ nlmclnt_setlockargs(req, fl); req->a_args.reclaim = 1; |
d11d10cc0 NLM/lockd: Ensure... |
632 633 |
status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_LOCK); if (status >= 0 && req->a_res.status == nlm_granted) |
1da177e4c Linux-2.6.12-rc2 |
634 635 636 637 638 |
return 0; printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " "(errno %d, status %d) ", fl->fl_pid, |
e8c5c045d [PATCH] lockd end... |
639 |
status, ntohl(req->a_res.status)); |
1da177e4c Linux-2.6.12-rc2 |
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 |
/* * FIXME: This is a serious failure. We can * * a. Ignore the problem * b. Send the owning process some signal (Linux doesn't have * SIGLOST, though...) * c. Retry the operation * * Until someone comes up with a simple implementation * for b or c, I'll choose option a. */ return -ENOLCK; } /* * UNLOCK: remove an existing lock */ static int nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) { |
28df955a2 NLM: Fix reclaim ... |
662 |
struct nlm_host *host = req->a_host; |
1da177e4c Linux-2.6.12-rc2 |
663 |
struct nlm_res *resp = &req->a_res; |
4a9af59fe NLM/lockd: Ensure... |
664 665 |
int status; unsigned char fl_flags = fl->fl_flags; |
1da177e4c Linux-2.6.12-rc2 |
666 |
|
26bcbf965 lockd: stop abusi... |
667 |
/* |
30f4e20a0 [PATCH] NLM: Ensu... |
668 669 670 671 |
* Note: the server is supposed to either grant us the unlock * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either * case, we want to unlock. */ |
9b0735749 NLM,NFSv4: Don't ... |
672 |
fl->fl_flags |= FL_EXISTS; |
28df955a2 NLM: Fix reclaim ... |
673 |
down_read(&host->h_rwsem); |
4a9af59fe NLM/lockd: Ensure... |
674 675 676 677 678 |
status = do_vfs_lock(fl); up_read(&host->h_rwsem); fl->fl_flags = fl_flags; if (status == -ENOENT) { status = 0; |
9b0735749 NLM,NFSv4: Don't ... |
679 680 |
goto out; } |
30f4e20a0 [PATCH] NLM: Ensu... |
681 |
|
dc9d8d048 NLM/lockd: conver... |
682 |
atomic_inc(&req->a_count); |
d11d10cc0 NLM/lockd: Ensure... |
683 684 |
status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); |
1da177e4c Linux-2.6.12-rc2 |
685 |
if (status < 0) |
92737230d NLM: Add nlmclnt_... |
686 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
687 |
|
e8c5c045d [PATCH] lockd end... |
688 |
if (resp->status == nlm_granted) |
92737230d NLM: Add nlmclnt_... |
689 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
690 |
|
e8c5c045d [PATCH] lockd end... |
691 |
if (resp->status != nlm_lck_denied_nolocks) |
82c2c8b86 lockd: properly c... |
692 693 694 |
printk("lockd: unexpected unlock status: %d ", ntohl(resp->status)); |
1da177e4c Linux-2.6.12-rc2 |
695 |
/* What to do now? I'm out of my depth... */ |
92737230d NLM: Add nlmclnt_... |
696 697 |
status = -ENOLCK; out: |
7db836d4a lockd: Split nlm_... |
698 |
nlmclnt_release_call(req); |
92737230d NLM: Add nlmclnt_... |
699 |
return status; |
1da177e4c Linux-2.6.12-rc2 |
700 |
} |
963d8fe53 RPC: Clean up RPC... |
701 |
static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) |
1da177e4c Linux-2.6.12-rc2 |
702 |
{ |
963d8fe53 RPC: Clean up RPC... |
703 |
struct nlm_rqst *req = data; |
e8c5c045d [PATCH] lockd end... |
704 |
u32 status = ntohl(req->a_res.status); |
1da177e4c Linux-2.6.12-rc2 |
705 706 707 708 709 710 711 |
if (RPC_ASSASSINATED(task)) goto die; if (task->tk_status < 0) { dprintk("lockd: unlock failed (err = %d) ", -task->tk_status); |
0b760113a NLM: Don't hang f... |
712 713 714 715 716 717 718 |
switch (task->tk_status) { case -EACCES: case -EIO: goto die; default: goto retry_rebind; } |
1da177e4c Linux-2.6.12-rc2 |
719 720 721 722 723 724 725 726 727 |
} if (status == NLM_LCK_DENIED_GRACE_PERIOD) { rpc_delay(task, NLMCLNT_GRACE_WAIT); goto retry_unlock; } if (status != NLM_LCK_GRANTED) printk(KERN_WARNING "lockd: unexpected unlock status: %d ", status); die: |
1da177e4c Linux-2.6.12-rc2 |
728 729 730 731 732 733 |
return; retry_rebind: nlm_rebind_host(req->a_host); retry_unlock: rpc_restart_call(task); } |
963d8fe53 RPC: Clean up RPC... |
734 735 |
static const struct rpc_call_ops nlmclnt_unlock_ops = { .rpc_call_done = nlmclnt_unlock_callback, |
92737230d NLM: Add nlmclnt_... |
736 |
.rpc_release = nlmclnt_rpc_release, |
963d8fe53 RPC: Clean up RPC... |
737 |
}; |
1da177e4c Linux-2.6.12-rc2 |
738 739 740 741 742 |
/* * Cancel a blocked lock request. * We always use an async RPC call for this in order not to hang a * process that has been Ctrl-C'ed. */ |
16fb24252 NLM: Fix argument... |
743 |
static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) |
1da177e4c Linux-2.6.12-rc2 |
744 745 |
{ struct nlm_rqst *req; |
6b4b3a752 NLM/lockd: Ensure... |
746 747 748 749 750 751 |
int status; dprintk("lockd: blocking lock attempt was interrupted by a signal. " " Attempting to cancel lock. "); |
1da177e4c Linux-2.6.12-rc2 |
752 |
|
92737230d NLM: Add nlmclnt_... |
753 |
req = nlm_alloc_call(nlm_get_host(host)); |
1da177e4c Linux-2.6.12-rc2 |
754 755 |
if (!req) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
756 757 758 |
req->a_flags = RPC_TASK_ASYNC; nlmclnt_setlockargs(req, fl); |
16fb24252 NLM: Fix argument... |
759 |
req->a_args.block = block; |
1da177e4c Linux-2.6.12-rc2 |
760 |
|
6b4b3a752 NLM/lockd: Ensure... |
761 |
atomic_inc(&req->a_count); |
d11d10cc0 NLM/lockd: Ensure... |
762 763 |
status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); |
6b4b3a752 NLM/lockd: Ensure... |
764 765 |
if (status == 0 && req->a_res.status == nlm_lck_denied) status = -ENOLCK; |
7db836d4a lockd: Split nlm_... |
766 |
nlmclnt_release_call(req); |
6b4b3a752 NLM/lockd: Ensure... |
767 |
return status; |
1da177e4c Linux-2.6.12-rc2 |
768 |
} |
963d8fe53 RPC: Clean up RPC... |
769 |
static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) |
1da177e4c Linux-2.6.12-rc2 |
770 |
{ |
963d8fe53 RPC: Clean up RPC... |
771 |
struct nlm_rqst *req = data; |
e8c5c045d [PATCH] lockd end... |
772 |
u32 status = ntohl(req->a_res.status); |
1da177e4c Linux-2.6.12-rc2 |
773 774 775 776 777 778 779 780 781 782 |
if (RPC_ASSASSINATED(task)) goto die; if (task->tk_status < 0) { dprintk("lockd: CANCEL call error %d, retrying. ", task->tk_status); goto retry_cancel; } |
c041b5ff8 NLM: fix print fo... |
783 784 |
dprintk("lockd: cancel status %u (task %u) ", |
e8c5c045d [PATCH] lockd end... |
785 |
status, task->tk_pid); |
1da177e4c Linux-2.6.12-rc2 |
786 |
|
e8c5c045d [PATCH] lockd end... |
787 |
switch (status) { |
1da177e4c Linux-2.6.12-rc2 |
788 789 |
case NLM_LCK_GRANTED: case NLM_LCK_DENIED_GRACE_PERIOD: |
35576cba5 NLM: nlmclnt_canc... |
790 |
case NLM_LCK_DENIED: |
1da177e4c Linux-2.6.12-rc2 |
791 792 793 794 795 796 797 798 799 |
/* Everything's good */ break; case NLM_LCK_DENIED_NOLOCKS: dprintk("lockd: CANCEL failed (server has no locks) "); goto retry_cancel; default: printk(KERN_NOTICE "lockd: weird return %d for CANCEL call ", |
e8c5c045d [PATCH] lockd end... |
800 |
status); |
1da177e4c Linux-2.6.12-rc2 |
801 802 803 |
} die: |
1da177e4c Linux-2.6.12-rc2 |
804 805 806 |
return; retry_cancel: |
aaaa99423 NLM: Ensure that ... |
807 808 809 |
/* Don't ever retry more than 3 times */ if (req->a_retries++ >= NLMCLNT_MAX_RETRIES) goto die; |
1da177e4c Linux-2.6.12-rc2 |
810 811 812 813 |
nlm_rebind_host(req->a_host); rpc_restart_call(task); rpc_delay(task, 30 * HZ); } |
963d8fe53 RPC: Clean up RPC... |
814 815 |
static const struct rpc_call_ops nlmclnt_cancel_ops = { .rpc_call_done = nlmclnt_cancel_callback, |
92737230d NLM: Add nlmclnt_... |
816 |
.rpc_release = nlmclnt_rpc_release, |
963d8fe53 RPC: Clean up RPC... |
817 |
}; |
1da177e4c Linux-2.6.12-rc2 |
818 819 820 821 |
/* * Convert an NLM status code to a generic kernel errno */ static int |
e8c5c045d [PATCH] lockd end... |
822 |
nlm_stat_to_errno(__be32 status) |
1da177e4c Linux-2.6.12-rc2 |
823 |
{ |
e8c5c045d [PATCH] lockd end... |
824 |
switch(ntohl(status)) { |
1da177e4c Linux-2.6.12-rc2 |
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 |
case NLM_LCK_GRANTED: return 0; case NLM_LCK_DENIED: return -EAGAIN; case NLM_LCK_DENIED_NOLOCKS: case NLM_LCK_DENIED_GRACE_PERIOD: return -ENOLCK; case NLM_LCK_BLOCKED: printk(KERN_NOTICE "lockd: unexpected status NLM_BLOCKED "); return -ENOLCK; #ifdef CONFIG_LOCKD_V4 case NLM_DEADLCK: return -EDEADLK; case NLM_ROFS: return -EROFS; case NLM_STALE_FH: return -ESTALE; case NLM_FBIG: return -EOVERFLOW; case NLM_FAILED: return -ENOLCK; #endif } |
82c2c8b86 lockd: properly c... |
849 850 851 |
printk(KERN_NOTICE "lockd: unexpected server status %d ", ntohl(status)); |
1da177e4c Linux-2.6.12-rc2 |
852 853 |
return -ENOLCK; } |