diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-07 15:34:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-07 15:34:24 -0400 |
commit | 2d56d3c43cc97ae48586745556f5a5b564d61582 (patch) | |
tree | 28f2edc1e69b79e94d99023041dd0358861b6956 | |
parent | 0f9008ef38d5a6305d94bbdd8f20d68fc75c63b6 (diff) | |
parent | 586759f03e2e9031ac5589912a51a909ed53c30a (diff) |
Merge branch 'server-cluster-locking-api' of git://linux-nfs.org/~bfields/linux
* 'server-cluster-locking-api' of git://linux-nfs.org/~bfields/linux:
gfs2: nfs lock support for gfs2
lockd: add code to handle deferred lock requests
lockd: always preallocate block in nlmsvc_lock()
lockd: handle test_lock deferrals
lockd: pass cookie in nlmsvc_testlock
lockd: handle fl_grant callbacks
lockd: save lock state on deferral
locks: add fl_grant callback for asynchronous lock return
nfsd4: Convert NFSv4 to new lock interface
locks: add lock cancel command
locks: allow {vfs,posix}_lock_file to return conflicting lock
locks: factor out generic/filesystem switch from setlock code
locks: factor out generic/filesystem switch from test_lock
locks: give posix_test_lock same interface as ->lock
locks: make ->lock release private data before returning in GETLK case
locks: create posix-to-flock helper functions
locks: trivial removal of unnecessary parentheses
-rw-r--r-- | fs/fuse/file.c | 3 | ||||
-rw-r--r-- | fs/gfs2/locking/dlm/plock.c | 109 | ||||
-rw-r--r-- | fs/gfs2/locking/nolock/main.c | 8 | ||||
-rw-r--r-- | fs/gfs2/ops_file.c | 12 | ||||
-rw-r--r-- | fs/lockd/svc4proc.c | 6 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 275 | ||||
-rw-r--r-- | fs/lockd/svcproc.c | 7 | ||||
-rw-r--r-- | fs/lockd/svcsubs.c | 2 | ||||
-rw-r--r-- | fs/locks.c | 264 | ||||
-rw-r--r-- | fs/nfs/file.c | 7 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 30 | ||||
-rw-r--r-- | include/linux/fcntl.h | 4 | ||||
-rw-r--r-- | include/linux/fs.h | 9 | ||||
-rw-r--r-- | include/linux/lockd/lockd.h | 14 |
15 files changed, 546 insertions, 205 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 2fd06927e851..acfad65a6e8e 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -738,8 +738,7 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) | |||
738 | 738 | ||
739 | if (cmd == F_GETLK) { | 739 | if (cmd == F_GETLK) { |
740 | if (fc->no_lock) { | 740 | if (fc->no_lock) { |
741 | if (!posix_test_lock(file, fl, fl)) | 741 | posix_test_lock(file, fl); |
742 | fl->fl_type = F_UNLCK; | ||
743 | err = 0; | 742 | err = 0; |
744 | } else | 743 | } else |
745 | err = fuse_getlk(file, fl); | 744 | err = fuse_getlk(file, fl); |
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 1dd4215b83d0..f82495e18c2d 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c | |||
@@ -25,6 +25,15 @@ struct plock_op { | |||
25 | struct gdlm_plock_info info; | 25 | struct gdlm_plock_info info; |
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct plock_xop { | ||
29 | struct plock_op xop; | ||
30 | void *callback; | ||
31 | void *fl; | ||
32 | void *file; | ||
33 | struct file_lock flc; | ||
34 | }; | ||
35 | |||
36 | |||
28 | static inline void set_version(struct gdlm_plock_info *info) | 37 | static inline void set_version(struct gdlm_plock_info *info) |
29 | { | 38 | { |
30 | info->version[0] = GDLM_PLOCK_VERSION_MAJOR; | 39 | info->version[0] = GDLM_PLOCK_VERSION_MAJOR; |
@@ -64,12 +73,14 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name, | |||
64 | { | 73 | { |
65 | struct gdlm_ls *ls = lockspace; | 74 | struct gdlm_ls *ls = lockspace; |
66 | struct plock_op *op; | 75 | struct plock_op *op; |
76 | struct plock_xop *xop; | ||
67 | int rv; | 77 | int rv; |
68 | 78 | ||
69 | op = kzalloc(sizeof(*op), GFP_KERNEL); | 79 | xop = kzalloc(sizeof(*xop), GFP_KERNEL); |
70 | if (!op) | 80 | if (!xop) |
71 | return -ENOMEM; | 81 | return -ENOMEM; |
72 | 82 | ||
83 | op = &xop->xop; | ||
73 | op->info.optype = GDLM_PLOCK_OP_LOCK; | 84 | op->info.optype = GDLM_PLOCK_OP_LOCK; |
74 | op->info.pid = fl->fl_pid; | 85 | op->info.pid = fl->fl_pid; |
75 | op->info.ex = (fl->fl_type == F_WRLCK); | 86 | op->info.ex = (fl->fl_type == F_WRLCK); |
@@ -79,9 +90,21 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name, | |||
79 | op->info.start = fl->fl_start; | 90 | op->info.start = fl->fl_start; |
80 | op->info.end = fl->fl_end; | 91 | op->info.end = fl->fl_end; |
81 | op->info.owner = (__u64)(long) fl->fl_owner; | 92 | op->info.owner = (__u64)(long) fl->fl_owner; |
93 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) { | ||
94 | xop->callback = fl->fl_lmops->fl_grant; | ||
95 | locks_init_lock(&xop->flc); | ||
96 | locks_copy_lock(&xop->flc, fl); | ||
97 | xop->fl = fl; | ||
98 | xop->file = file; | ||
99 | } else | ||
100 | xop->callback = NULL; | ||
82 | 101 | ||
83 | send_op(op); | 102 | send_op(op); |
84 | wait_event(recv_wq, (op->done != 0)); | 103 | |
104 | if (xop->callback == NULL) | ||
105 | wait_event(recv_wq, (op->done != 0)); | ||
106 | else | ||
107 | return -EINPROGRESS; | ||
85 | 108 | ||
86 | spin_lock(&ops_lock); | 109 | spin_lock(&ops_lock); |
87 | if (!list_empty(&op->list)) { | 110 | if (!list_empty(&op->list)) { |
@@ -99,7 +122,63 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name, | |||
99 | (unsigned long long)name->ln_number); | 122 | (unsigned long long)name->ln_number); |
100 | } | 123 | } |
101 | 124 | ||
102 | kfree(op); | 125 | kfree(xop); |
126 | return rv; | ||
127 | } | ||
128 | |||
129 | /* Returns failure iff a succesful lock operation should be canceled */ | ||
130 | static int gdlm_plock_callback(struct plock_op *op) | ||
131 | { | ||
132 | struct file *file; | ||
133 | struct file_lock *fl; | ||
134 | struct file_lock *flc; | ||
135 | int (*notify)(void *, void *, int) = NULL; | ||
136 | struct plock_xop *xop = (struct plock_xop *)op; | ||
137 | int rv = 0; | ||
138 | |||
139 | spin_lock(&ops_lock); | ||
140 | if (!list_empty(&op->list)) { | ||
141 | printk(KERN_INFO "plock op on list\n"); | ||
142 | list_del(&op->list); | ||
143 | } | ||
144 | spin_unlock(&ops_lock); | ||
145 | |||
146 | /* check if the following 2 are still valid or make a copy */ | ||
147 | file = xop->file; | ||
148 | flc = &xop->flc; | ||
149 | fl = xop->fl; | ||
150 | notify = xop->callback; | ||
151 | |||
152 | if (op->info.rv) { | ||
153 | notify(flc, NULL, op->info.rv); | ||
154 | goto out; | ||
155 | } | ||
156 | |||
157 | /* got fs lock; bookkeep locally as well: */ | ||
158 | flc->fl_flags &= ~FL_SLEEP; | ||
159 | if (posix_lock_file(file, flc, NULL)) { | ||
160 | /* | ||
161 | * This can only happen in the case of kmalloc() failure. | ||
162 | * The filesystem's own lock is the authoritative lock, | ||
163 | * so a failure to get the lock locally is not a disaster. | ||
164 | * As long as GFS cannot reliably cancel locks (especially | ||
165 | * in a low-memory situation), we're better off ignoring | ||
166 | * this failure than trying to recover. | ||
167 | */ | ||
168 | log_error("gdlm_plock: vfs lock error file %p fl %p", | ||
169 | file, fl); | ||
170 | } | ||
171 | |||
172 | rv = notify(flc, NULL, 0); | ||
173 | if (rv) { | ||
174 | /* XXX: We need to cancel the fs lock here: */ | ||
175 | printk("gfs2 lock granted after lock request failed;" | ||
176 | " dangling lock!\n"); | ||
177 | goto out; | ||
178 | } | ||
179 | |||
180 | out: | ||
181 | kfree(xop); | ||
103 | return rv; | 182 | return rv; |
104 | } | 183 | } |
105 | 184 | ||
@@ -138,6 +217,9 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name, | |||
138 | 217 | ||
139 | rv = op->info.rv; | 218 | rv = op->info.rv; |
140 | 219 | ||
220 | if (rv == -ENOENT) | ||
221 | rv = 0; | ||
222 | |||
141 | kfree(op); | 223 | kfree(op); |
142 | return rv; | 224 | return rv; |
143 | } | 225 | } |
@@ -161,6 +243,7 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name, | |||
161 | op->info.start = fl->fl_start; | 243 | op->info.start = fl->fl_start; |
162 | op->info.end = fl->fl_end; | 244 | op->info.end = fl->fl_end; |
163 | 245 | ||
246 | |||
164 | send_op(op); | 247 | send_op(op); |
165 | wait_event(recv_wq, (op->done != 0)); | 248 | wait_event(recv_wq, (op->done != 0)); |
166 | 249 | ||
@@ -173,9 +256,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name, | |||
173 | 256 | ||
174 | rv = op->info.rv; | 257 | rv = op->info.rv; |
175 | 258 | ||
176 | if (rv == 0) | 259 | fl->fl_type = F_UNLCK; |
177 | fl->fl_type = F_UNLCK; | 260 | if (rv == -ENOENT) |
178 | else if (rv > 0) { | 261 | rv = 0; |
262 | else if (rv == 0 && op->info.pid != fl->fl_pid) { | ||
179 | fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK; | 263 | fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK; |
180 | fl->fl_pid = op->info.pid; | 264 | fl->fl_pid = op->info.pid; |
181 | fl->fl_start = op->info.start; | 265 | fl->fl_start = op->info.start; |
@@ -243,9 +327,14 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, | |||
243 | } | 327 | } |
244 | spin_unlock(&ops_lock); | 328 | spin_unlock(&ops_lock); |
245 | 329 | ||
246 | if (found) | 330 | if (found) { |
247 | wake_up(&recv_wq); | 331 | struct plock_xop *xop; |
248 | else | 332 | xop = (struct plock_xop *)op; |
333 | if (xop->callback) | ||
334 | count = gdlm_plock_callback(op); | ||
335 | else | ||
336 | wake_up(&recv_wq); | ||
337 | } else | ||
249 | printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid, | 338 | printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid, |
250 | (unsigned long long)info.number); | 339 | (unsigned long long)info.number); |
251 | return count; | 340 | return count; |
diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c index acfbc941f319..5cc1dfa7944a 100644 --- a/fs/gfs2/locking/nolock/main.c +++ b/fs/gfs2/locking/nolock/main.c | |||
@@ -164,13 +164,7 @@ static void nolock_unhold_lvb(void *lock, char *lvb) | |||
164 | static int nolock_plock_get(void *lockspace, struct lm_lockname *name, | 164 | static int nolock_plock_get(void *lockspace, struct lm_lockname *name, |
165 | struct file *file, struct file_lock *fl) | 165 | struct file *file, struct file_lock *fl) |
166 | { | 166 | { |
167 | struct file_lock tmp; | 167 | posix_test_lock(file, fl); |
168 | int ret; | ||
169 | |||
170 | ret = posix_test_lock(file, fl, &tmp); | ||
171 | fl->fl_type = F_UNLCK; | ||
172 | if (ret) | ||
173 | memcpy(fl, &tmp, sizeof(struct file_lock)); | ||
174 | 168 | ||
175 | return 0; | 169 | return 0; |
176 | } | 170 | } |
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index b50180e22779..329c4dcdecdb 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c | |||
@@ -513,18 +513,18 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) | |||
513 | 513 | ||
514 | if (sdp->sd_args.ar_localflocks) { | 514 | if (sdp->sd_args.ar_localflocks) { |
515 | if (IS_GETLK(cmd)) { | 515 | if (IS_GETLK(cmd)) { |
516 | struct file_lock tmp; | 516 | posix_test_lock(file, fl); |
517 | int ret; | ||
518 | ret = posix_test_lock(file, fl, &tmp); | ||
519 | fl->fl_type = F_UNLCK; | ||
520 | if (ret) | ||
521 | memcpy(fl, &tmp, sizeof(struct file_lock)); | ||
522 | return 0; | 517 | return 0; |
523 | } else { | 518 | } else { |
524 | return posix_lock_file_wait(file, fl); | 519 | return posix_lock_file_wait(file, fl); |
525 | } | 520 | } |
526 | } | 521 | } |
527 | 522 | ||
523 | if (cmd == F_CANCELLK) { | ||
524 | /* Hack: */ | ||
525 | cmd = F_SETLK; | ||
526 | fl->fl_type = F_UNLCK; | ||
527 | } | ||
528 | if (IS_GETLK(cmd)) | 528 | if (IS_GETLK(cmd)) |
529 | return gfs2_lm_plock_get(sdp, &name, file, fl); | 529 | return gfs2_lm_plock_get(sdp, &name, file, fl); |
530 | else if (fl->fl_type == F_UNLCK) | 530 | else if (fl->fl_type == F_UNLCK) |
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 47a66aa5d55b..bf27b6c6cb6b 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
@@ -99,7 +99,9 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
99 | return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; | 99 | return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; |
100 | 100 | ||
101 | /* Now check for conflicting locks */ | 101 | /* Now check for conflicting locks */ |
102 | resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock); | 102 | resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie); |
103 | if (resp->status == nlm_drop_reply) | ||
104 | return rpc_drop_reply; | ||
103 | 105 | ||
104 | dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); | 106 | dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); |
105 | nlm_release_host(host); | 107 | nlm_release_host(host); |
@@ -143,6 +145,8 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
143 | /* Now try to lock the file */ | 145 | /* Now try to lock the file */ |
144 | resp->status = nlmsvc_lock(rqstp, file, &argp->lock, | 146 | resp->status = nlmsvc_lock(rqstp, file, &argp->lock, |
145 | argp->block, &argp->cookie); | 147 | argp->block, &argp->cookie); |
148 | if (resp->status == nlm_drop_reply) | ||
149 | return rpc_drop_reply; | ||
146 | 150 | ||
147 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); | 151 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); |
148 | nlm_release_host(host); | 152 | nlm_release_host(host); |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index cf51f849e76c..b3efa4536cc5 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -173,7 +173,7 @@ found: | |||
173 | */ | 173 | */ |
174 | static inline struct nlm_block * | 174 | static inline struct nlm_block * |
175 | nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, | 175 | nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, |
176 | struct nlm_lock *lock, struct nlm_cookie *cookie) | 176 | struct nlm_lock *lock, struct nlm_cookie *cookie) |
177 | { | 177 | { |
178 | struct nlm_block *block; | 178 | struct nlm_block *block; |
179 | struct nlm_host *host; | 179 | struct nlm_host *host; |
@@ -210,6 +210,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, | |||
210 | block->b_daemon = rqstp->rq_server; | 210 | block->b_daemon = rqstp->rq_server; |
211 | block->b_host = host; | 211 | block->b_host = host; |
212 | block->b_file = file; | 212 | block->b_file = file; |
213 | block->b_fl = NULL; | ||
213 | file->f_count++; | 214 | file->f_count++; |
214 | 215 | ||
215 | /* Add to file's list of blocks */ | 216 | /* Add to file's list of blocks */ |
@@ -261,6 +262,7 @@ static void nlmsvc_free_block(struct kref *kref) | |||
261 | nlmsvc_freegrantargs(block->b_call); | 262 | nlmsvc_freegrantargs(block->b_call); |
262 | nlm_release_call(block->b_call); | 263 | nlm_release_call(block->b_call); |
263 | nlm_release_file(block->b_file); | 264 | nlm_release_file(block->b_file); |
265 | kfree(block->b_fl); | ||
264 | kfree(block); | 266 | kfree(block); |
265 | } | 267 | } |
266 | 268 | ||
@@ -331,6 +333,31 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call) | |||
331 | } | 333 | } |
332 | 334 | ||
333 | /* | 335 | /* |
336 | * Deferred lock request handling for non-blocking lock | ||
337 | */ | ||
338 | static u32 | ||
339 | nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block) | ||
340 | { | ||
341 | u32 status = nlm_lck_denied_nolocks; | ||
342 | |||
343 | block->b_flags |= B_QUEUED; | ||
344 | |||
345 | nlmsvc_insert_block(block, NLM_TIMEOUT); | ||
346 | |||
347 | block->b_cache_req = &rqstp->rq_chandle; | ||
348 | if (rqstp->rq_chandle.defer) { | ||
349 | block->b_deferred_req = | ||
350 | rqstp->rq_chandle.defer(block->b_cache_req); | ||
351 | if (block->b_deferred_req != NULL) | ||
352 | status = nlm_drop_reply; | ||
353 | } | ||
354 | dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n", | ||
355 | block, block->b_flags, status); | ||
356 | |||
357 | return status; | ||
358 | } | ||
359 | |||
360 | /* | ||
334 | * Attempt to establish a lock, and if it can't be granted, block it | 361 | * Attempt to establish a lock, and if it can't be granted, block it |
335 | * if required. | 362 | * if required. |
336 | */ | 363 | */ |
@@ -338,7 +365,7 @@ __be32 | |||
338 | nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, | 365 | nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, |
339 | struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) | 366 | struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) |
340 | { | 367 | { |
341 | struct nlm_block *block, *newblock = NULL; | 368 | struct nlm_block *block = NULL; |
342 | int error; | 369 | int error; |
343 | __be32 ret; | 370 | __be32 ret; |
344 | 371 | ||
@@ -351,29 +378,58 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, | |||
351 | wait); | 378 | wait); |
352 | 379 | ||
353 | 380 | ||
354 | lock->fl.fl_flags &= ~FL_SLEEP; | ||
355 | again: | ||
356 | /* Lock file against concurrent access */ | 381 | /* Lock file against concurrent access */ |
357 | mutex_lock(&file->f_mutex); | 382 | mutex_lock(&file->f_mutex); |
358 | /* Get existing block (in case client is busy-waiting) */ | 383 | /* Get existing block (in case client is busy-waiting) |
384 | * or create new block | ||
385 | */ | ||
359 | block = nlmsvc_lookup_block(file, lock); | 386 | block = nlmsvc_lookup_block(file, lock); |
360 | if (block == NULL) { | 387 | if (block == NULL) { |
361 | if (newblock != NULL) | 388 | block = nlmsvc_create_block(rqstp, file, lock, cookie); |
362 | lock = &newblock->b_call->a_args.lock; | 389 | ret = nlm_lck_denied_nolocks; |
363 | } else | 390 | if (block == NULL) |
391 | goto out; | ||
364 | lock = &block->b_call->a_args.lock; | 392 | lock = &block->b_call->a_args.lock; |
393 | } else | ||
394 | lock->fl.fl_flags &= ~FL_SLEEP; | ||
365 | 395 | ||
366 | error = posix_lock_file(file->f_file, &lock->fl); | 396 | if (block->b_flags & B_QUEUED) { |
367 | lock->fl.fl_flags &= ~FL_SLEEP; | 397 | dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n", |
398 | block, block->b_flags); | ||
399 | if (block->b_granted) { | ||
400 | nlmsvc_unlink_block(block); | ||
401 | ret = nlm_granted; | ||
402 | goto out; | ||
403 | } | ||
404 | if (block->b_flags & B_TIMED_OUT) { | ||
405 | nlmsvc_unlink_block(block); | ||
406 | ret = nlm_lck_denied; | ||
407 | goto out; | ||
408 | } | ||
409 | ret = nlm_drop_reply; | ||
410 | goto out; | ||
411 | } | ||
368 | 412 | ||
369 | dprintk("lockd: posix_lock_file returned %d\n", error); | 413 | if (!wait) |
414 | lock->fl.fl_flags &= ~FL_SLEEP; | ||
415 | error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); | ||
416 | lock->fl.fl_flags &= ~FL_SLEEP; | ||
370 | 417 | ||
418 | dprintk("lockd: vfs_lock_file returned %d\n", error); | ||
371 | switch(error) { | 419 | switch(error) { |
372 | case 0: | 420 | case 0: |
373 | ret = nlm_granted; | 421 | ret = nlm_granted; |
374 | goto out; | 422 | goto out; |
375 | case -EAGAIN: | 423 | case -EAGAIN: |
424 | ret = nlm_lck_denied; | ||
376 | break; | 425 | break; |
426 | case -EINPROGRESS: | ||
427 | if (wait) | ||
428 | break; | ||
429 | /* Filesystem lock operation is in progress | ||
430 | Add it to the queue waiting for callback */ | ||
431 | ret = nlmsvc_defer_lock_rqst(rqstp, block); | ||
432 | goto out; | ||
377 | case -EDEADLK: | 433 | case -EDEADLK: |
378 | ret = nlm_deadlock; | 434 | ret = nlm_deadlock; |
379 | goto out; | 435 | goto out; |
@@ -387,26 +443,11 @@ again: | |||
387 | goto out; | 443 | goto out; |
388 | 444 | ||
389 | ret = nlm_lck_blocked; | 445 | ret = nlm_lck_blocked; |
390 | if (block != NULL) | ||
391 | goto out; | ||
392 | |||
393 | /* If we don't have a block, create and initialize it. Then | ||
394 | * retry because we may have slept in kmalloc. */ | ||
395 | /* We have to release f_mutex as nlmsvc_create_block may try to | ||
396 | * to claim it while doing host garbage collection */ | ||
397 | if (newblock == NULL) { | ||
398 | mutex_unlock(&file->f_mutex); | ||
399 | dprintk("lockd: blocking on this lock (allocating).\n"); | ||
400 | if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie))) | ||
401 | return nlm_lck_denied_nolocks; | ||
402 | goto again; | ||
403 | } | ||
404 | 446 | ||
405 | /* Append to list of blocked */ | 447 | /* Append to list of blocked */ |
406 | nlmsvc_insert_block(newblock, NLM_NEVER); | 448 | nlmsvc_insert_block(block, NLM_NEVER); |
407 | out: | 449 | out: |
408 | mutex_unlock(&file->f_mutex); | 450 | mutex_unlock(&file->f_mutex); |
409 | nlmsvc_release_block(newblock); | ||
410 | nlmsvc_release_block(block); | 451 | nlmsvc_release_block(block); |
411 | dprintk("lockd: nlmsvc_lock returned %u\n", ret); | 452 | dprintk("lockd: nlmsvc_lock returned %u\n", ret); |
412 | return ret; | 453 | return ret; |
@@ -416,9 +457,14 @@ out: | |||
416 | * Test for presence of a conflicting lock. | 457 | * Test for presence of a conflicting lock. |
417 | */ | 458 | */ |
418 | __be32 | 459 | __be32 |
419 | nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, | 460 | nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, |
420 | struct nlm_lock *conflock) | 461 | struct nlm_lock *lock, struct nlm_lock *conflock, |
462 | struct nlm_cookie *cookie) | ||
421 | { | 463 | { |
464 | struct nlm_block *block = NULL; | ||
465 | int error; | ||
466 | __be32 ret; | ||
467 | |||
422 | dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", | 468 | dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", |
423 | file->f_file->f_path.dentry->d_inode->i_sb->s_id, | 469 | file->f_file->f_path.dentry->d_inode->i_sb->s_id, |
424 | file->f_file->f_path.dentry->d_inode->i_ino, | 470 | file->f_file->f_path.dentry->d_inode->i_ino, |
@@ -426,19 +472,70 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, | |||
426 | (long long)lock->fl.fl_start, | 472 | (long long)lock->fl.fl_start, |
427 | (long long)lock->fl.fl_end); | 473 | (long long)lock->fl.fl_end); |
428 | 474 | ||
429 | if (posix_test_lock(file->f_file, &lock->fl, &conflock->fl)) { | 475 | /* Get existing block (in case client is busy-waiting) */ |
430 | dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", | 476 | block = nlmsvc_lookup_block(file, lock); |
431 | conflock->fl.fl_type, | 477 | |
432 | (long long)conflock->fl.fl_start, | 478 | if (block == NULL) { |
433 | (long long)conflock->fl.fl_end); | 479 | struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL); |
434 | conflock->caller = "somehost"; /* FIXME */ | 480 | |
435 | conflock->len = strlen(conflock->caller); | 481 | if (conf == NULL) |
436 | conflock->oh.len = 0; /* don't return OH info */ | 482 | return nlm_granted; |
437 | conflock->svid = conflock->fl.fl_pid; | 483 | block = nlmsvc_create_block(rqstp, file, lock, cookie); |
438 | return nlm_lck_denied; | 484 | if (block == NULL) { |
485 | kfree(conf); | ||
486 | return nlm_granted; | ||
487 | } | ||
488 | block->b_fl = conf; | ||
489 | } | ||
490 | if (block->b_flags & B_QUEUED) { | ||
491 | dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n", | ||
492 | block, block->b_flags, block->b_fl); | ||
493 | if (block->b_flags & B_TIMED_OUT) { | ||
494 | nlmsvc_unlink_block(block); | ||
495 | return nlm_lck_denied; | ||
496 | } | ||
497 | if (block->b_flags & B_GOT_CALLBACK) { | ||
498 | if (block->b_fl != NULL | ||
499 | && block->b_fl->fl_type != F_UNLCK) { | ||
500 | lock->fl = *block->b_fl; | ||
501 | goto conf_lock; | ||
502 | } | ||
503 | else { | ||
504 | nlmsvc_unlink_block(block); | ||
505 | return nlm_granted; | ||
506 | } | ||
507 | } | ||
508 | return nlm_drop_reply; | ||
439 | } | 509 | } |
440 | 510 | ||
441 | return nlm_granted; | 511 | error = vfs_test_lock(file->f_file, &lock->fl); |
512 | if (error == -EINPROGRESS) | ||
513 | return nlmsvc_defer_lock_rqst(rqstp, block); | ||
514 | if (error) { | ||
515 | ret = nlm_lck_denied_nolocks; | ||
516 | goto out; | ||
517 | } | ||
518 | if (lock->fl.fl_type == F_UNLCK) { | ||
519 | ret = nlm_granted; | ||
520 | goto out; | ||
521 | } | ||
522 | |||
523 | conf_lock: | ||
524 | dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", | ||
525 | lock->fl.fl_type, (long long)lock->fl.fl_start, | ||
526 | (long long)lock->fl.fl_end); | ||
527 | conflock->caller = "somehost"; /* FIXME */ | ||
528 | conflock->len = strlen(conflock->caller); | ||
529 | conflock->oh.len = 0; /* don't return OH info */ | ||
530 | conflock->svid = lock->fl.fl_pid; | ||
531 | conflock->fl.fl_type = lock->fl.fl_type; | ||
532 | conflock->fl.fl_start = lock->fl.fl_start; | ||
533 | conflock->fl.fl_end = lock->fl.fl_end; | ||
534 | ret = nlm_lck_denied; | ||
535 | out: | ||
536 | if (block) | ||
537 | nlmsvc_release_block(block); | ||
538 | return ret; | ||
442 | } | 539 | } |
443 | 540 | ||
444 | /* | 541 | /* |
@@ -464,7 +561,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) | |||
464 | nlmsvc_cancel_blocked(file, lock); | 561 | nlmsvc_cancel_blocked(file, lock); |
465 | 562 | ||
466 | lock->fl.fl_type = F_UNLCK; | 563 | lock->fl.fl_type = F_UNLCK; |
467 | error = posix_lock_file(file->f_file, &lock->fl); | 564 | error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); |
468 | 565 | ||
469 | return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; | 566 | return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; |
470 | } | 567 | } |
@@ -493,6 +590,8 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) | |||
493 | block = nlmsvc_lookup_block(file, lock); | 590 | block = nlmsvc_lookup_block(file, lock); |
494 | mutex_unlock(&file->f_mutex); | 591 | mutex_unlock(&file->f_mutex); |
495 | if (block != NULL) { | 592 | if (block != NULL) { |
593 | vfs_cancel_lock(block->b_file->f_file, | ||
594 | &block->b_call->a_args.lock.fl); | ||
496 | status = nlmsvc_unlink_block(block); | 595 | status = nlmsvc_unlink_block(block); |
497 | nlmsvc_release_block(block); | 596 | nlmsvc_release_block(block); |
498 | } | 597 | } |
@@ -500,6 +599,63 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) | |||
500 | } | 599 | } |
501 | 600 | ||
502 | /* | 601 | /* |
602 | * This is a callback from the filesystem for VFS file lock requests. | ||
603 | * It will be used if fl_grant is defined and the filesystem can not | ||
604 | * respond to the request immediately. | ||
605 | * For GETLK request it will copy the reply to the nlm_block. | ||
606 | * For SETLK or SETLKW request it will get the local posix lock. | ||
607 | * In all cases it will move the block to the head of nlm_blocked q where | ||
608 | * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the | ||
609 | * deferred rpc for GETLK and SETLK. | ||
610 | */ | ||
611 | static void | ||
612 | nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf, | ||
613 | int result) | ||
614 | { | ||
615 | block->b_flags |= B_GOT_CALLBACK; | ||
616 | if (result == 0) | ||
617 | block->b_granted = 1; | ||
618 | else | ||
619 | block->b_flags |= B_TIMED_OUT; | ||
620 | if (conf) { | ||
621 | if (block->b_fl) | ||
622 | locks_copy_lock(block->b_fl, conf); | ||
623 | } | ||
624 | } | ||
625 | |||
626 | static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf, | ||
627 | int result) | ||
628 | { | ||
629 | struct nlm_block *block; | ||
630 | int rc = -ENOENT; | ||
631 | |||
632 | lock_kernel(); | ||
633 | list_for_each_entry(block, &nlm_blocked, b_list) { | ||
634 | if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) { | ||
635 | dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n", | ||
636 | block, block->b_flags); | ||
637 | if (block->b_flags & B_QUEUED) { | ||
638 | if (block->b_flags & B_TIMED_OUT) { | ||
639 | rc = -ENOLCK; | ||
640 | break; | ||
641 | } | ||
642 | nlmsvc_update_deferred_block(block, conf, result); | ||
643 | } else if (result == 0) | ||
644 | block->b_granted = 1; | ||
645 | |||
646 | nlmsvc_insert_block(block, 0); | ||
647 | svc_wake_up(block->b_daemon); | ||
648 | rc = 0; | ||
649 | break; | ||
650 | } | ||
651 | } | ||
652 | unlock_kernel(); | ||
653 | if (rc == -ENOENT) | ||
654 | printk(KERN_WARNING "lockd: grant for unknown block\n"); | ||
655 | return rc; | ||
656 | } | ||
657 | |||
658 | /* | ||
503 | * Unblock a blocked lock request. This is a callback invoked from the | 659 | * Unblock a blocked lock request. This is a callback invoked from the |
504 | * VFS layer when a lock on which we blocked is removed. | 660 | * VFS layer when a lock on which we blocked is removed. |
505 | * | 661 | * |
@@ -531,6 +687,7 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2) | |||
531 | struct lock_manager_operations nlmsvc_lock_operations = { | 687 | struct lock_manager_operations nlmsvc_lock_operations = { |
532 | .fl_compare_owner = nlmsvc_same_owner, | 688 | .fl_compare_owner = nlmsvc_same_owner, |
533 | .fl_notify = nlmsvc_notify_blocked, | 689 | .fl_notify = nlmsvc_notify_blocked, |
690 | .fl_grant = nlmsvc_grant_deferred, | ||
534 | }; | 691 | }; |
535 | 692 | ||
536 | /* | 693 | /* |
@@ -553,6 +710,8 @@ nlmsvc_grant_blocked(struct nlm_block *block) | |||
553 | 710 | ||
554 | dprintk("lockd: grant blocked lock %p\n", block); | 711 | dprintk("lockd: grant blocked lock %p\n", block); |
555 | 712 | ||
713 | kref_get(&block->b_count); | ||
714 | |||
556 | /* Unlink block request from list */ | 715 | /* Unlink block request from list */ |
557 | nlmsvc_unlink_block(block); | 716 | nlmsvc_unlink_block(block); |
558 | 717 | ||
@@ -566,20 +725,23 @@ nlmsvc_grant_blocked(struct nlm_block *block) | |||
566 | 725 | ||
567 | /* Try the lock operation again */ | 726 | /* Try the lock operation again */ |
568 | lock->fl.fl_flags |= FL_SLEEP; | 727 | lock->fl.fl_flags |= FL_SLEEP; |
569 | error = posix_lock_file(file->f_file, &lock->fl); | 728 | error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); |
570 | lock->fl.fl_flags &= ~FL_SLEEP; | 729 | lock->fl.fl_flags &= ~FL_SLEEP; |
571 | 730 | ||
572 | switch (error) { | 731 | switch (error) { |
573 | case 0: | 732 | case 0: |
574 | break; | 733 | break; |
575 | case -EAGAIN: | 734 | case -EAGAIN: |
576 | dprintk("lockd: lock still blocked\n"); | 735 | case -EINPROGRESS: |
736 | dprintk("lockd: lock still blocked error %d\n", error); | ||
577 | nlmsvc_insert_block(block, NLM_NEVER); | 737 | nlmsvc_insert_block(block, NLM_NEVER); |
738 | nlmsvc_release_block(block); | ||
578 | return; | 739 | return; |
579 | default: | 740 | default: |
580 | printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", | 741 | printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", |
581 | -error, __FUNCTION__); | 742 | -error, __FUNCTION__); |
582 | nlmsvc_insert_block(block, 10 * HZ); | 743 | nlmsvc_insert_block(block, 10 * HZ); |
744 | nlmsvc_release_block(block); | ||
583 | return; | 745 | return; |
584 | } | 746 | } |
585 | 747 | ||
@@ -592,7 +754,6 @@ callback: | |||
592 | nlmsvc_insert_block(block, 30 * HZ); | 754 | nlmsvc_insert_block(block, 30 * HZ); |
593 | 755 | ||
594 | /* Call the client */ | 756 | /* Call the client */ |
595 | kref_get(&block->b_count); | ||
596 | nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops); | 757 | nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops); |
597 | } | 758 | } |
598 | 759 | ||
@@ -665,6 +826,23 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status) | |||
665 | nlmsvc_release_block(block); | 826 | nlmsvc_release_block(block); |
666 | } | 827 | } |
667 | 828 | ||
829 | /* Helper function to handle retry of a deferred block. | ||
830 | * If it is a blocking lock, call grant_blocked. | ||
831 | * For a non-blocking lock or test lock, revisit the request. | ||
832 | */ | ||
833 | static void | ||
834 | retry_deferred_block(struct nlm_block *block) | ||
835 | { | ||
836 | if (!(block->b_flags & B_GOT_CALLBACK)) | ||
837 | block->b_flags |= B_TIMED_OUT; | ||
838 | nlmsvc_insert_block(block, NLM_TIMEOUT); | ||
839 | dprintk("revisit block %p flags %d\n", block, block->b_flags); | ||
840 | if (block->b_deferred_req) { | ||
841 | block->b_deferred_req->revisit(block->b_deferred_req, 0); | ||
842 | block->b_deferred_req = NULL; | ||
843 | } | ||
844 | } | ||
845 | |||
668 | /* | 846 | /* |
669 | * Retry all blocked locks that have been notified. This is where lockd | 847 | * Retry all blocked locks that have been notified. This is where lockd |
670 | * picks up locks that can be granted, or grant notifications that must | 848 | * picks up locks that can be granted, or grant notifications that must |
@@ -688,9 +866,12 @@ nlmsvc_retry_blocked(void) | |||
688 | 866 | ||
689 | dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", | 867 | dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", |
690 | block, block->b_when); | 868 | block, block->b_when); |
691 | kref_get(&block->b_count); | 869 | if (block->b_flags & B_QUEUED) { |
692 | nlmsvc_grant_blocked(block); | 870 | dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n", |
693 | nlmsvc_release_block(block); | 871 | block, block->b_granted, block->b_flags); |
872 | retry_deferred_block(block); | ||
873 | } else | ||
874 | nlmsvc_grant_blocked(block); | ||
694 | } | 875 | } |
695 | 876 | ||
696 | return timeout; | 877 | return timeout; |
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 31cb48425733..9cd5c8b37593 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c | |||
@@ -33,6 +33,7 @@ cast_to_nlm(__be32 status, u32 vers) | |||
33 | case nlm_lck_denied_nolocks: | 33 | case nlm_lck_denied_nolocks: |
34 | case nlm_lck_blocked: | 34 | case nlm_lck_blocked: |
35 | case nlm_lck_denied_grace_period: | 35 | case nlm_lck_denied_grace_period: |
36 | case nlm_drop_reply: | ||
36 | break; | 37 | break; |
37 | case nlm4_deadlock: | 38 | case nlm4_deadlock: |
38 | status = nlm_lck_denied; | 39 | status = nlm_lck_denied; |
@@ -127,7 +128,9 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
127 | return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; | 128 | return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; |
128 | 129 | ||
129 | /* Now check for conflicting locks */ | 130 | /* Now check for conflicting locks */ |
130 | resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock)); | 131 | resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie)); |
132 | if (resp->status == nlm_drop_reply) | ||
133 | return rpc_drop_reply; | ||
131 | 134 | ||
132 | dprintk("lockd: TEST status %d vers %d\n", | 135 | dprintk("lockd: TEST status %d vers %d\n", |
133 | ntohl(resp->status), rqstp->rq_vers); | 136 | ntohl(resp->status), rqstp->rq_vers); |
@@ -172,6 +175,8 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
172 | /* Now try to lock the file */ | 175 | /* Now try to lock the file */ |
173 | resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock, | 176 | resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock, |
174 | argp->block, &argp->cookie)); | 177 | argp->block, &argp->cookie)); |
178 | if (resp->status == nlm_drop_reply) | ||
179 | return rpc_drop_reply; | ||
175 | 180 | ||
176 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); | 181 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); |
177 | nlm_release_host(host); | 182 | nlm_release_host(host); |
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index c0df00c74ce3..84ebba33b98d 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -182,7 +182,7 @@ again: | |||
182 | lock.fl_type = F_UNLCK; | 182 | lock.fl_type = F_UNLCK; |
183 | lock.fl_start = 0; | 183 | lock.fl_start = 0; |
184 | lock.fl_end = OFFSET_MAX; | 184 | lock.fl_end = OFFSET_MAX; |
185 | if (posix_lock_file(file->f_file, &lock) < 0) { | 185 | if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) { |
186 | printk("lockd: unlock failure in %s:%d\n", | 186 | printk("lockd: unlock failure in %s:%d\n", |
187 | __FILE__, __LINE__); | 187 | __FILE__, __LINE__); |
188 | return 1; | 188 | return 1; |
diff --git a/fs/locks.c b/fs/locks.c index 325578074742..671a034dc999 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -665,11 +665,11 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w | |||
665 | } | 665 | } |
666 | 666 | ||
667 | int | 667 | int |
668 | posix_test_lock(struct file *filp, struct file_lock *fl, | 668 | posix_test_lock(struct file *filp, struct file_lock *fl) |
669 | struct file_lock *conflock) | ||
670 | { | 669 | { |
671 | struct file_lock *cfl; | 670 | struct file_lock *cfl; |
672 | 671 | ||
672 | fl->fl_type = F_UNLCK; | ||
673 | lock_kernel(); | 673 | lock_kernel(); |
674 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { | 674 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { |
675 | if (!IS_POSIX(cfl)) | 675 | if (!IS_POSIX(cfl)) |
@@ -678,7 +678,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl, | |||
678 | break; | 678 | break; |
679 | } | 679 | } |
680 | if (cfl) { | 680 | if (cfl) { |
681 | __locks_copy_lock(conflock, cfl); | 681 | __locks_copy_lock(fl, cfl); |
682 | unlock_kernel(); | 682 | unlock_kernel(); |
683 | return 1; | 683 | return 1; |
684 | } | 684 | } |
@@ -800,7 +800,7 @@ out: | |||
800 | return error; | 800 | return error; |
801 | } | 801 | } |
802 | 802 | ||
803 | static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) | 803 | static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock) |
804 | { | 804 | { |
805 | struct file_lock *fl; | 805 | struct file_lock *fl; |
806 | struct file_lock *new_fl = NULL; | 806 | struct file_lock *new_fl = NULL; |
@@ -1006,6 +1006,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request | |||
1006 | * posix_lock_file - Apply a POSIX-style lock to a file | 1006 | * posix_lock_file - Apply a POSIX-style lock to a file |
1007 | * @filp: The file to apply the lock to | 1007 | * @filp: The file to apply the lock to |
1008 | * @fl: The lock to be applied | 1008 | * @fl: The lock to be applied |
1009 | * @conflock: Place to return a copy of the conflicting lock, if found. | ||
1009 | * | 1010 | * |
1010 | * Add a POSIX style lock to a file. | 1011 | * Add a POSIX style lock to a file. |
1011 | * We merge adjacent & overlapping locks whenever possible. | 1012 | * We merge adjacent & overlapping locks whenever possible. |
@@ -1015,26 +1016,12 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request | |||
1015 | * whether or not a lock was successfully freed by testing the return | 1016 | * whether or not a lock was successfully freed by testing the return |
1016 | * value for -ENOENT. | 1017 | * value for -ENOENT. |
1017 | */ | 1018 | */ |
1018 | int posix_lock_file(struct file *filp, struct file_lock *fl) | 1019 | int posix_lock_file(struct file *filp, struct file_lock *fl, |
1019 | { | ||
1020 | return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL); | ||
1021 | } | ||
1022 | EXPORT_SYMBOL(posix_lock_file); | ||
1023 | |||
1024 | /** | ||
1025 | * posix_lock_file_conf - Apply a POSIX-style lock to a file | ||
1026 | * @filp: The file to apply the lock to | ||
1027 | * @fl: The lock to be applied | ||
1028 | * @conflock: Place to return a copy of the conflicting lock, if found. | ||
1029 | * | ||
1030 | * Except for the conflock parameter, acts just like posix_lock_file. | ||
1031 | */ | ||
1032 | int posix_lock_file_conf(struct file *filp, struct file_lock *fl, | ||
1033 | struct file_lock *conflock) | 1020 | struct file_lock *conflock) |
1034 | { | 1021 | { |
1035 | return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock); | 1022 | return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock); |
1036 | } | 1023 | } |
1037 | EXPORT_SYMBOL(posix_lock_file_conf); | 1024 | EXPORT_SYMBOL(posix_lock_file); |
1038 | 1025 | ||
1039 | /** | 1026 | /** |
1040 | * posix_lock_file_wait - Apply a POSIX-style lock to a file | 1027 | * posix_lock_file_wait - Apply a POSIX-style lock to a file |
@@ -1050,7 +1037,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl) | |||
1050 | int error; | 1037 | int error; |
1051 | might_sleep (); | 1038 | might_sleep (); |
1052 | for (;;) { | 1039 | for (;;) { |
1053 | error = posix_lock_file(filp, fl); | 1040 | error = posix_lock_file(filp, fl, NULL); |
1054 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) | 1041 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) |
1055 | break; | 1042 | break; |
1056 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); | 1043 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); |
@@ -1122,7 +1109,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, | |||
1122 | fl.fl_end = offset + count - 1; | 1109 | fl.fl_end = offset + count - 1; |
1123 | 1110 | ||
1124 | for (;;) { | 1111 | for (;;) { |
1125 | error = __posix_lock_file_conf(inode, &fl, NULL); | 1112 | error = __posix_lock_file(inode, &fl, NULL); |
1126 | if (error != -EAGAIN) | 1113 | if (error != -EAGAIN) |
1127 | break; | 1114 | break; |
1128 | if (!(fl.fl_flags & FL_SLEEP)) | 1115 | if (!(fl.fl_flags & FL_SLEEP)) |
@@ -1610,12 +1597,62 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) | |||
1610 | return error; | 1597 | return error; |
1611 | } | 1598 | } |
1612 | 1599 | ||
1600 | /** | ||
1601 | * vfs_test_lock - test file byte range lock | ||
1602 | * @filp: The file to test lock for | ||
1603 | * @fl: The lock to test | ||
1604 | * @conf: Place to return a copy of the conflicting lock, if found | ||
1605 | * | ||
1606 | * Returns -ERRNO on failure. Indicates presence of conflicting lock by | ||
1607 | * setting conf->fl_type to something other than F_UNLCK. | ||
1608 | */ | ||
1609 | int vfs_test_lock(struct file *filp, struct file_lock *fl) | ||
1610 | { | ||
1611 | if (filp->f_op && filp->f_op->lock) | ||
1612 | return filp->f_op->lock(filp, F_GETLK, fl); | ||
1613 | posix_test_lock(filp, fl); | ||
1614 | return 0; | ||
1615 | } | ||
1616 | EXPORT_SYMBOL_GPL(vfs_test_lock); | ||
1617 | |||
1618 | static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) | ||
1619 | { | ||
1620 | flock->l_pid = fl->fl_pid; | ||
1621 | #if BITS_PER_LONG == 32 | ||
1622 | /* | ||
1623 | * Make sure we can represent the posix lock via | ||
1624 | * legacy 32bit flock. | ||
1625 | */ | ||
1626 | if (fl->fl_start > OFFT_OFFSET_MAX) | ||
1627 | return -EOVERFLOW; | ||
1628 | if (fl->fl_end != OFFSET_MAX && fl->fl_end > OFFT_OFFSET_MAX) | ||
1629 | return -EOVERFLOW; | ||
1630 | #endif | ||
1631 | flock->l_start = fl->fl_start; | ||
1632 | flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : | ||
1633 | fl->fl_end - fl->fl_start + 1; | ||
1634 | flock->l_whence = 0; | ||
1635 | return 0; | ||
1636 | } | ||
1637 | |||
1638 | #if BITS_PER_LONG == 32 | ||
1639 | static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) | ||
1640 | { | ||
1641 | flock->l_pid = fl->fl_pid; | ||
1642 | flock->l_start = fl->fl_start; | ||
1643 | flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : | ||
1644 | fl->fl_end - fl->fl_start + 1; | ||
1645 | flock->l_whence = 0; | ||
1646 | flock->l_type = fl->fl_type; | ||
1647 | } | ||
1648 | #endif | ||
1649 | |||
1613 | /* Report the first existing lock that would conflict with l. | 1650 | /* Report the first existing lock that would conflict with l. |
1614 | * This implements the F_GETLK command of fcntl(). | 1651 | * This implements the F_GETLK command of fcntl(). |
1615 | */ | 1652 | */ |
1616 | int fcntl_getlk(struct file *filp, struct flock __user *l) | 1653 | int fcntl_getlk(struct file *filp, struct flock __user *l) |
1617 | { | 1654 | { |
1618 | struct file_lock *fl, cfl, file_lock; | 1655 | struct file_lock file_lock; |
1619 | struct flock flock; | 1656 | struct flock flock; |
1620 | int error; | 1657 | int error; |
1621 | 1658 | ||
@@ -1630,38 +1667,15 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) | |||
1630 | if (error) | 1667 | if (error) |
1631 | goto out; | 1668 | goto out; |
1632 | 1669 | ||
1633 | if (filp->f_op && filp->f_op->lock) { | 1670 | error = vfs_test_lock(filp, &file_lock); |
1634 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); | 1671 | if (error) |
1635 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | 1672 | goto out; |
1636 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
1637 | if (error < 0) | ||
1638 | goto out; | ||
1639 | else | ||
1640 | fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); | ||
1641 | } else { | ||
1642 | fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL); | ||
1643 | } | ||
1644 | 1673 | ||
1645 | flock.l_type = F_UNLCK; | 1674 | flock.l_type = file_lock.fl_type; |
1646 | if (fl != NULL) { | 1675 | if (file_lock.fl_type != F_UNLCK) { |
1647 | flock.l_pid = fl->fl_pid; | 1676 | error = posix_lock_to_flock(&flock, &file_lock); |
1648 | #if BITS_PER_LONG == 32 | 1677 | if (error) |
1649 | /* | ||
1650 | * Make sure we can represent the posix lock via | ||
1651 | * legacy 32bit flock. | ||
1652 | */ | ||
1653 | error = -EOVERFLOW; | ||
1654 | if (fl->fl_start > OFFT_OFFSET_MAX) | ||
1655 | goto out; | ||
1656 | if ((fl->fl_end != OFFSET_MAX) | ||
1657 | && (fl->fl_end > OFFT_OFFSET_MAX)) | ||
1658 | goto out; | 1678 | goto out; |
1659 | #endif | ||
1660 | flock.l_start = fl->fl_start; | ||
1661 | flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : | ||
1662 | fl->fl_end - fl->fl_start + 1; | ||
1663 | flock.l_whence = 0; | ||
1664 | flock.l_type = fl->fl_type; | ||
1665 | } | 1679 | } |
1666 | error = -EFAULT; | 1680 | error = -EFAULT; |
1667 | if (!copy_to_user(l, &flock, sizeof(flock))) | 1681 | if (!copy_to_user(l, &flock, sizeof(flock))) |
@@ -1670,6 +1684,48 @@ out: | |||
1670 | return error; | 1684 | return error; |
1671 | } | 1685 | } |
1672 | 1686 | ||
1687 | /** | ||
1688 | * vfs_lock_file - file byte range lock | ||
1689 | * @filp: The file to apply the lock to | ||
1690 | * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.) | ||
1691 | * @fl: The lock to be applied | ||
1692 | * @conf: Place to return a copy of the conflicting lock, if found. | ||
1693 | * | ||
1694 | * A caller that doesn't care about the conflicting lock may pass NULL | ||
1695 | * as the final argument. | ||
1696 | * | ||
1697 | * If the filesystem defines a private ->lock() method, then @conf will | ||
1698 | * be left unchanged; so a caller that cares should initialize it to | ||
1699 | * some acceptable default. | ||
1700 | * | ||
1701 | * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX | ||
1702 | * locks, the ->lock() interface may return asynchronously, before the lock has | ||
1703 | * been granted or denied by the underlying filesystem, if (and only if) | ||
1704 | * fl_grant is set. Callers expecting ->lock() to return asynchronously | ||
1705 | * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if) | ||
1706 | * the request is for a blocking lock. When ->lock() does return asynchronously, | ||
1707 | * it must return -EINPROGRESS, and call ->fl_grant() when the lock | ||
1708 | * request completes. | ||
1709 | * If the request is for non-blocking lock the file system should return | ||
1710 | * -EINPROGRESS then try to get the lock and call the callback routine with | ||
1711 | * the result. If the request timed out the callback routine will return a | ||
1712 | * nonzero return code and the file system should release the lock. The file | ||
1713 | * system is also responsible to keep a corresponding posix lock when it | ||
1714 | * grants a lock so the VFS can find out which locks are locally held and do | ||
1715 | * the correct lock cleanup when required. | ||
1716 | * The underlying filesystem must not drop the kernel lock or call | ||
1717 | * ->fl_grant() before returning to the caller with a -EINPROGRESS | ||
1718 | * return code. | ||
1719 | */ | ||
1720 | int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) | ||
1721 | { | ||
1722 | if (filp->f_op && filp->f_op->lock) | ||
1723 | return filp->f_op->lock(filp, cmd, fl); | ||
1724 | else | ||
1725 | return posix_lock_file(filp, fl, conf); | ||
1726 | } | ||
1727 | EXPORT_SYMBOL_GPL(vfs_lock_file); | ||
1728 | |||
1673 | /* Apply the lock described by l to an open file descriptor. | 1729 | /* Apply the lock described by l to an open file descriptor. |
1674 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). | 1730 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). |
1675 | */ | 1731 | */ |
@@ -1732,21 +1788,17 @@ again: | |||
1732 | if (error) | 1788 | if (error) |
1733 | goto out; | 1789 | goto out; |
1734 | 1790 | ||
1735 | if (filp->f_op && filp->f_op->lock != NULL) | 1791 | for (;;) { |
1736 | error = filp->f_op->lock(filp, cmd, file_lock); | 1792 | error = vfs_lock_file(filp, cmd, file_lock, NULL); |
1737 | else { | 1793 | if (error != -EAGAIN || cmd == F_SETLK) |
1738 | for (;;) { | ||
1739 | error = posix_lock_file(filp, file_lock); | ||
1740 | if ((error != -EAGAIN) || (cmd == F_SETLK)) | ||
1741 | break; | ||
1742 | error = wait_event_interruptible(file_lock->fl_wait, | ||
1743 | !file_lock->fl_next); | ||
1744 | if (!error) | ||
1745 | continue; | ||
1746 | |||
1747 | locks_delete_block(file_lock); | ||
1748 | break; | 1794 | break; |
1749 | } | 1795 | error = wait_event_interruptible(file_lock->fl_wait, |
1796 | !file_lock->fl_next); | ||
1797 | if (!error) | ||
1798 | continue; | ||
1799 | |||
1800 | locks_delete_block(file_lock); | ||
1801 | break; | ||
1750 | } | 1802 | } |
1751 | 1803 | ||
1752 | /* | 1804 | /* |
@@ -1769,7 +1821,7 @@ out: | |||
1769 | */ | 1821 | */ |
1770 | int fcntl_getlk64(struct file *filp, struct flock64 __user *l) | 1822 | int fcntl_getlk64(struct file *filp, struct flock64 __user *l) |
1771 | { | 1823 | { |
1772 | struct file_lock *fl, cfl, file_lock; | 1824 | struct file_lock file_lock; |
1773 | struct flock64 flock; | 1825 | struct flock64 flock; |
1774 | int error; | 1826 | int error; |
1775 | 1827 | ||
@@ -1784,27 +1836,14 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l) | |||
1784 | if (error) | 1836 | if (error) |
1785 | goto out; | 1837 | goto out; |
1786 | 1838 | ||
1787 | if (filp->f_op && filp->f_op->lock) { | 1839 | error = vfs_test_lock(filp, &file_lock); |
1788 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); | 1840 | if (error) |
1789 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | 1841 | goto out; |
1790 | file_lock.fl_ops->fl_release_private(&file_lock); | 1842 | |
1791 | if (error < 0) | 1843 | flock.l_type = file_lock.fl_type; |
1792 | goto out; | 1844 | if (file_lock.fl_type != F_UNLCK) |
1793 | else | 1845 | posix_lock_to_flock64(&flock, &file_lock); |
1794 | fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); | 1846 | |
1795 | } else { | ||
1796 | fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL); | ||
1797 | } | ||
1798 | |||
1799 | flock.l_type = F_UNLCK; | ||
1800 | if (fl != NULL) { | ||
1801 | flock.l_pid = fl->fl_pid; | ||
1802 | flock.l_start = fl->fl_start; | ||
1803 | flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : | ||
1804 | fl->fl_end - fl->fl_start + 1; | ||
1805 | flock.l_whence = 0; | ||
1806 | flock.l_type = fl->fl_type; | ||
1807 | } | ||
1808 | error = -EFAULT; | 1847 | error = -EFAULT; |
1809 | if (!copy_to_user(l, &flock, sizeof(flock))) | 1848 | if (!copy_to_user(l, &flock, sizeof(flock))) |
1810 | error = 0; | 1849 | error = 0; |
@@ -1875,21 +1914,17 @@ again: | |||
1875 | if (error) | 1914 | if (error) |
1876 | goto out; | 1915 | goto out; |
1877 | 1916 | ||
1878 | if (filp->f_op && filp->f_op->lock != NULL) | 1917 | for (;;) { |
1879 | error = filp->f_op->lock(filp, cmd, file_lock); | 1918 | error = vfs_lock_file(filp, cmd, file_lock, NULL); |
1880 | else { | 1919 | if (error != -EAGAIN || cmd == F_SETLK64) |
1881 | for (;;) { | ||
1882 | error = posix_lock_file(filp, file_lock); | ||
1883 | if ((error != -EAGAIN) || (cmd == F_SETLK64)) | ||
1884 | break; | ||
1885 | error = wait_event_interruptible(file_lock->fl_wait, | ||
1886 | !file_lock->fl_next); | ||
1887 | if (!error) | ||
1888 | continue; | ||
1889 | |||
1890 | locks_delete_block(file_lock); | ||
1891 | break; | 1920 | break; |
1892 | } | 1921 | error = wait_event_interruptible(file_lock->fl_wait, |
1922 | !file_lock->fl_next); | ||
1923 | if (!error) | ||
1924 | continue; | ||
1925 | |||
1926 | locks_delete_block(file_lock); | ||
1927 | break; | ||
1893 | } | 1928 | } |
1894 | 1929 | ||
1895 | /* | 1930 | /* |
@@ -1934,10 +1969,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner) | |||
1934 | lock.fl_ops = NULL; | 1969 | lock.fl_ops = NULL; |
1935 | lock.fl_lmops = NULL; | 1970 | lock.fl_lmops = NULL; |
1936 | 1971 | ||
1937 | if (filp->f_op && filp->f_op->lock != NULL) | 1972 | vfs_lock_file(filp, F_SETLK, &lock, NULL); |
1938 | filp->f_op->lock(filp, F_SETLK, &lock); | ||
1939 | else | ||
1940 | posix_lock_file(filp, &lock); | ||
1941 | 1973 | ||
1942 | if (lock.fl_ops && lock.fl_ops->fl_release_private) | 1974 | if (lock.fl_ops && lock.fl_ops->fl_release_private) |
1943 | lock.fl_ops->fl_release_private(&lock); | 1975 | lock.fl_ops->fl_release_private(&lock); |
@@ -2014,6 +2046,22 @@ posix_unblock_lock(struct file *filp, struct file_lock *waiter) | |||
2014 | 2046 | ||
2015 | EXPORT_SYMBOL(posix_unblock_lock); | 2047 | EXPORT_SYMBOL(posix_unblock_lock); |
2016 | 2048 | ||
2049 | /** | ||
2050 | * vfs_cancel_lock - file byte range unblock lock | ||
2051 | * @filp: The file to apply the unblock to | ||
2052 | * @fl: The lock to be unblocked | ||
2053 | * | ||
2054 | * Used by lock managers to cancel blocked requests | ||
2055 | */ | ||
2056 | int vfs_cancel_lock(struct file *filp, struct file_lock *fl) | ||
2057 | { | ||
2058 | if (filp->f_op && filp->f_op->lock) | ||
2059 | return filp->f_op->lock(filp, F_CANCELLK, fl); | ||
2060 | return 0; | ||
2061 | } | ||
2062 | |||
2063 | EXPORT_SYMBOL_GPL(vfs_cancel_lock); | ||
2064 | |||
2017 | static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) | 2065 | static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) |
2018 | { | 2066 | { |
2019 | struct inode *inode = NULL; | 2067 | struct inode *inode = NULL; |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 8e66b5a2d490..5eaee6dd040b 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -391,17 +391,12 @@ out_swapfile: | |||
391 | 391 | ||
392 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) | 392 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) |
393 | { | 393 | { |
394 | struct file_lock cfl; | ||
395 | struct inode *inode = filp->f_mapping->host; | 394 | struct inode *inode = filp->f_mapping->host; |
396 | int status = 0; | 395 | int status = 0; |
397 | 396 | ||
398 | lock_kernel(); | 397 | lock_kernel(); |
399 | /* Try local locking first */ | 398 | /* Try local locking first */ |
400 | if (posix_test_lock(filp, fl, &cfl)) { | 399 | if (posix_test_lock(filp, fl)) { |
401 | fl->fl_start = cfl.fl_start; | ||
402 | fl->fl_end = cfl.fl_end; | ||
403 | fl->fl_type = cfl.fl_type; | ||
404 | fl->fl_pid = cfl.fl_pid; | ||
405 | goto out; | 400 | goto out; |
406 | } | 401 | } |
407 | 402 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3b5ca1b15fe9..d6a30e965787 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -3017,6 +3017,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3017 | case -NFS4ERR_DENIED: | 3017 | case -NFS4ERR_DENIED: |
3018 | status = 0; | 3018 | status = 0; |
3019 | } | 3019 | } |
3020 | request->fl_ops->fl_release_private(request); | ||
3020 | out: | 3021 | out: |
3021 | up_read(&clp->cl_sem); | 3022 | up_read(&clp->cl_sem); |
3022 | return status; | 3023 | return status; |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index af360705e551..678f3be88ac0 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/nfsd/xdr4.h> | 50 | #include <linux/nfsd/xdr4.h> |
51 | #include <linux/namei.h> | 51 | #include <linux/namei.h> |
52 | #include <linux/mutex.h> | 52 | #include <linux/mutex.h> |
53 | #include <linux/lockd/bind.h> | ||
53 | 54 | ||
54 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 55 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
55 | 56 | ||
@@ -2657,6 +2658,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2657 | struct file_lock conflock; | 2658 | struct file_lock conflock; |
2658 | __be32 status = 0; | 2659 | __be32 status = 0; |
2659 | unsigned int strhashval; | 2660 | unsigned int strhashval; |
2661 | unsigned int cmd; | ||
2660 | int err; | 2662 | int err; |
2661 | 2663 | ||
2662 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", | 2664 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", |
@@ -2739,10 +2741,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2739 | case NFS4_READ_LT: | 2741 | case NFS4_READ_LT: |
2740 | case NFS4_READW_LT: | 2742 | case NFS4_READW_LT: |
2741 | file_lock.fl_type = F_RDLCK; | 2743 | file_lock.fl_type = F_RDLCK; |
2744 | cmd = F_SETLK; | ||
2742 | break; | 2745 | break; |
2743 | case NFS4_WRITE_LT: | 2746 | case NFS4_WRITE_LT: |
2744 | case NFS4_WRITEW_LT: | 2747 | case NFS4_WRITEW_LT: |
2745 | file_lock.fl_type = F_WRLCK; | 2748 | file_lock.fl_type = F_WRLCK; |
2749 | cmd = F_SETLK; | ||
2746 | break; | 2750 | break; |
2747 | default: | 2751 | default: |
2748 | status = nfserr_inval; | 2752 | status = nfserr_inval; |
@@ -2769,9 +2773,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2769 | 2773 | ||
2770 | /* XXX?: Just to divert the locks_release_private at the start of | 2774 | /* XXX?: Just to divert the locks_release_private at the start of |
2771 | * locks_copy_lock: */ | 2775 | * locks_copy_lock: */ |
2772 | conflock.fl_ops = NULL; | 2776 | locks_init_lock(&conflock); |
2773 | conflock.fl_lmops = NULL; | 2777 | err = vfs_lock_file(filp, cmd, &file_lock, &conflock); |
2774 | err = posix_lock_file_conf(filp, &file_lock, &conflock); | ||
2775 | switch (-err) { | 2778 | switch (-err) { |
2776 | case 0: /* success! */ | 2779 | case 0: /* success! */ |
2777 | update_stateid(&lock_stp->st_stateid); | 2780 | update_stateid(&lock_stp->st_stateid); |
@@ -2788,7 +2791,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2788 | status = nfserr_deadlock; | 2791 | status = nfserr_deadlock; |
2789 | break; | 2792 | break; |
2790 | default: | 2793 | default: |
2791 | dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",err); | 2794 | dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); |
2792 | status = nfserr_resource; | 2795 | status = nfserr_resource; |
2793 | break; | 2796 | break; |
2794 | } | 2797 | } |
@@ -2813,7 +2816,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2813 | struct inode *inode; | 2816 | struct inode *inode; |
2814 | struct file file; | 2817 | struct file file; |
2815 | struct file_lock file_lock; | 2818 | struct file_lock file_lock; |
2816 | struct file_lock conflock; | 2819 | int error; |
2817 | __be32 status; | 2820 | __be32 status; |
2818 | 2821 | ||
2819 | if (nfs4_in_grace()) | 2822 | if (nfs4_in_grace()) |
@@ -2869,18 +2872,23 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2869 | 2872 | ||
2870 | nfs4_transform_lock_offset(&file_lock); | 2873 | nfs4_transform_lock_offset(&file_lock); |
2871 | 2874 | ||
2872 | /* posix_test_lock uses the struct file _only_ to resolve the inode. | 2875 | /* vfs_test_lock uses the struct file _only_ to resolve the inode. |
2873 | * since LOCKT doesn't require an OPEN, and therefore a struct | 2876 | * since LOCKT doesn't require an OPEN, and therefore a struct |
2874 | * file may not exist, pass posix_test_lock a struct file with | 2877 | * file may not exist, pass vfs_test_lock a struct file with |
2875 | * only the dentry:inode set. | 2878 | * only the dentry:inode set. |
2876 | */ | 2879 | */ |
2877 | memset(&file, 0, sizeof (struct file)); | 2880 | memset(&file, 0, sizeof (struct file)); |
2878 | file.f_path.dentry = cstate->current_fh.fh_dentry; | 2881 | file.f_path.dentry = cstate->current_fh.fh_dentry; |
2879 | 2882 | ||
2880 | status = nfs_ok; | 2883 | status = nfs_ok; |
2881 | if (posix_test_lock(&file, &file_lock, &conflock)) { | 2884 | error = vfs_test_lock(&file, &file_lock); |
2885 | if (error) { | ||
2886 | status = nfserrno(error); | ||
2887 | goto out; | ||
2888 | } | ||
2889 | if (file_lock.fl_type != F_UNLCK) { | ||
2882 | status = nfserr_denied; | 2890 | status = nfserr_denied; |
2883 | nfs4_set_lock_denied(&conflock, &lockt->lt_denied); | 2891 | nfs4_set_lock_denied(&file_lock, &lockt->lt_denied); |
2884 | } | 2892 | } |
2885 | out: | 2893 | out: |
2886 | nfs4_unlock_state(); | 2894 | nfs4_unlock_state(); |
@@ -2933,9 +2941,9 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2933 | /* | 2941 | /* |
2934 | * Try to unlock the file in the VFS. | 2942 | * Try to unlock the file in the VFS. |
2935 | */ | 2943 | */ |
2936 | err = posix_lock_file(filp, &file_lock); | 2944 | err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL); |
2937 | if (err) { | 2945 | if (err) { |
2938 | dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); | 2946 | dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); |
2939 | goto out_nfserr; | 2947 | goto out_nfserr; |
2940 | } | 2948 | } |
2941 | /* | 2949 | /* |
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h index 996f5611cd59..40b93265d4ba 100644 --- a/include/linux/fcntl.h +++ b/include/linux/fcntl.h | |||
@@ -3,6 +3,10 @@ | |||
3 | 3 | ||
4 | #include <asm/fcntl.h> | 4 | #include <asm/fcntl.h> |
5 | 5 | ||
6 | /* Cancel a blocking posix lock; internal use only until we expose an | ||
7 | * asynchronous lock api to userspace: */ | ||
8 | #define F_CANCELLK (F_LINUX_SPECIFIC_BASE+5) | ||
9 | |||
6 | #define F_SETLEASE (F_LINUX_SPECIFIC_BASE+0) | 10 | #define F_SETLEASE (F_LINUX_SPECIFIC_BASE+0) |
7 | #define F_GETLEASE (F_LINUX_SPECIFIC_BASE+1) | 11 | #define F_GETLEASE (F_LINUX_SPECIFIC_BASE+1) |
8 | 12 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 55a74ffa7e3b..bc6d27cecaac 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -786,6 +786,7 @@ struct file_lock_operations { | |||
786 | struct lock_manager_operations { | 786 | struct lock_manager_operations { |
787 | int (*fl_compare_owner)(struct file_lock *, struct file_lock *); | 787 | int (*fl_compare_owner)(struct file_lock *, struct file_lock *); |
788 | void (*fl_notify)(struct file_lock *); /* unblock callback */ | 788 | void (*fl_notify)(struct file_lock *); /* unblock callback */ |
789 | int (*fl_grant)(struct file_lock *, struct file_lock *, int); | ||
789 | void (*fl_copy_lock)(struct file_lock *, struct file_lock *); | 790 | void (*fl_copy_lock)(struct file_lock *, struct file_lock *); |
790 | void (*fl_release_private)(struct file_lock *); | 791 | void (*fl_release_private)(struct file_lock *); |
791 | void (*fl_break)(struct file_lock *); | 792 | void (*fl_break)(struct file_lock *); |
@@ -857,11 +858,13 @@ extern void locks_init_lock(struct file_lock *); | |||
857 | extern void locks_copy_lock(struct file_lock *, struct file_lock *); | 858 | extern void locks_copy_lock(struct file_lock *, struct file_lock *); |
858 | extern void locks_remove_posix(struct file *, fl_owner_t); | 859 | extern void locks_remove_posix(struct file *, fl_owner_t); |
859 | extern void locks_remove_flock(struct file *); | 860 | extern void locks_remove_flock(struct file *); |
860 | extern int posix_test_lock(struct file *, struct file_lock *, struct file_lock *); | 861 | extern int posix_test_lock(struct file *, struct file_lock *); |
861 | extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_lock *); | 862 | extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); |
862 | extern int posix_lock_file(struct file *, struct file_lock *); | ||
863 | extern int posix_lock_file_wait(struct file *, struct file_lock *); | 863 | extern int posix_lock_file_wait(struct file *, struct file_lock *); |
864 | extern int posix_unblock_lock(struct file *, struct file_lock *); | 864 | extern int posix_unblock_lock(struct file *, struct file_lock *); |
865 | extern int vfs_test_lock(struct file *, struct file_lock *); | ||
866 | extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *); | ||
867 | extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl); | ||
865 | extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); | 868 | extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); |
866 | extern int __break_lease(struct inode *inode, unsigned int flags); | 869 | extern int __break_lease(struct inode *inode, unsigned int flags); |
867 | extern void lease_get_mtime(struct inode *, struct timespec *time); | 870 | extern void lease_get_mtime(struct inode *, struct timespec *time); |
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index f6a81e0b1b93..05707e2fccae 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
@@ -119,6 +119,9 @@ struct nlm_file { | |||
119 | * couldn't be granted because of a conflicting lock). | 119 | * couldn't be granted because of a conflicting lock). |
120 | */ | 120 | */ |
121 | #define NLM_NEVER (~(unsigned long) 0) | 121 | #define NLM_NEVER (~(unsigned long) 0) |
122 | /* timeout on non-blocking call: */ | ||
123 | #define NLM_TIMEOUT (7 * HZ) | ||
124 | |||
122 | struct nlm_block { | 125 | struct nlm_block { |
123 | struct kref b_count; /* Reference count */ | 126 | struct kref b_count; /* Reference count */ |
124 | struct list_head b_list; /* linked list of all blocks */ | 127 | struct list_head b_list; /* linked list of all blocks */ |
@@ -130,6 +133,13 @@ struct nlm_block { | |||
130 | unsigned int b_id; /* block id */ | 133 | unsigned int b_id; /* block id */ |
131 | unsigned char b_granted; /* VFS granted lock */ | 134 | unsigned char b_granted; /* VFS granted lock */ |
132 | struct nlm_file * b_file; /* file in question */ | 135 | struct nlm_file * b_file; /* file in question */ |
136 | struct cache_req * b_cache_req; /* deferred request handling */ | ||
137 | struct file_lock * b_fl; /* set for GETLK */ | ||
138 | struct cache_deferred_req * b_deferred_req; | ||
139 | unsigned int b_flags; /* block flags */ | ||
140 | #define B_QUEUED 1 /* lock queued */ | ||
141 | #define B_GOT_CALLBACK 2 /* got lock or conflicting lock */ | ||
142 | #define B_TIMED_OUT 4 /* filesystem too slow to respond */ | ||
133 | }; | 143 | }; |
134 | 144 | ||
135 | /* | 145 | /* |
@@ -185,8 +195,8 @@ typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref) | |||
185 | __be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, | 195 | __be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, |
186 | struct nlm_lock *, int, struct nlm_cookie *); | 196 | struct nlm_lock *, int, struct nlm_cookie *); |
187 | __be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); | 197 | __be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); |
188 | __be32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *, | 198 | __be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *, |
189 | struct nlm_lock *); | 199 | struct nlm_lock *, struct nlm_lock *, struct nlm_cookie *); |
190 | __be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); | 200 | __be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); |
191 | unsigned long nlmsvc_retry_blocked(void); | 201 | unsigned long nlmsvc_retry_blocked(void); |
192 | void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, | 202 | void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, |