diff options
| -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 *, |
