Blame view
fs/locks.c
73.4 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
/* * linux/fs/locks.c * * Provide support for fcntl()'s F_GETLK, F_SETLK, and F_SETLKW calls. * Doug Evans (dje@spiff.uucp), August 07, 1992 * * Deadlock detection added. * FIXME: one thing isn't handled yet: * - mandatory locks (requires lots of changes elsewhere) * Kelly Carmichael (kelly@[142.24.8.65]), September 17, 1994. * * Miscellaneous edits, and a total rewrite of posix_lock_file() code. * Kai Petzke (wpp@marie.physik.tu-berlin.de), 1994 * * Converted file_lock_table to a linked list from an array, which eliminates * the limits on how many active file locks are open. * Chad Page (pageone@netcom.com), November 27, 1994 * * Removed dependency on file descriptors. dup()'ed file descriptors now * get the same locks as the original file descriptors, and a close() on * any file descriptor removes ALL the locks on the file for the current * process. Since locks still depend on the process id, locks are inherited * after an exec() but not after a fork(). This agrees with POSIX, and both * BSD and SVR4 practice. * Andy Walker (andy@lysaker.kvaerner.no), February 14, 1995 * * Scrapped free list which is redundant now that we allocate locks * dynamically with kmalloc()/kfree(). * Andy Walker (andy@lysaker.kvaerner.no), February 21, 1995 * * Implemented two lock personalities - FL_FLOCK and FL_POSIX. * * FL_POSIX locks are created with calls to fcntl() and lockf() through the * fcntl() system call. They have the semantics described above. * * FL_FLOCK locks are created with calls to flock(), through the flock() * system call, which is new. Old C libraries implement flock() via fcntl() * and will continue to use the old, broken implementation. * * FL_FLOCK locks follow the 4.4 BSD flock() semantics. They are associated * with a file pointer (filp). As a result they can be shared by a parent * process and its children after a fork(). They are removed when the last * file descriptor referring to the file pointer is closed (unless explicitly * unlocked). * * FL_FLOCK locks never deadlock, an existing lock is always removed before * upgrading from shared to exclusive (or vice versa). When this happens * any processes blocked by the current lock are woken up and allowed to * run before the new lock is applied. * Andy Walker (andy@lysaker.kvaerner.no), June 09, 1995 * * Removed some race conditions in flock_lock_file(), marked other possible * races. Just grep for FIXME to see them. * Dmitry Gorodchanin (pgmdsg@ibi.com), February 09, 1996. * * Addressed Dmitry's concerns. Deadlock checking no longer recursive. * Lock allocation changed to GFP_ATOMIC as we can't afford to sleep * once we've checked for blocking and deadlocking. * Andy Walker (andy@lysaker.kvaerner.no), April 03, 1996. * * Initial implementation of mandatory locks. SunOS turned out to be * a rotten model, so I implemented the "obvious" semantics. |
395cf9691
|
63 |
* See 'Documentation/filesystems/mandatory-locking.txt' for details. |
1da177e4c
|
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
* Andy Walker (andy@lysaker.kvaerner.no), April 06, 1996. * * Don't allow mandatory locks on mmap()'ed files. Added simple functions to * check if a file has mandatory locks, used by mmap(), open() and creat() to * see if system call should be rejected. Ref. HP-UX/SunOS/Solaris Reference * Manual, Section 2. * Andy Walker (andy@lysaker.kvaerner.no), April 09, 1996. * * Tidied up block list handling. Added '/proc/locks' interface. * Andy Walker (andy@lysaker.kvaerner.no), April 24, 1996. * * Fixed deadlock condition for pathological code that mixes calls to * flock() and fcntl(). * Andy Walker (andy@lysaker.kvaerner.no), April 29, 1996. * * Allow only one type of locking scheme (FL_POSIX or FL_FLOCK) to be in use * for a given file at a time. Changed the CONFIG_LOCK_MANDATORY scheme to * guarantee sensible behaviour in the case where file system modules might * be compiled with different options than the kernel itself. * Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996. * * Added a couple of missing wake_up() calls. Thanks to Thomas Meckel * (Thomas.Meckel@mni.fh-giessen.de) for spotting this. * Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996. * * Changed FL_POSIX locks to use the block list in the same way as FL_FLOCK * locks. Changed process synchronisation to avoid dereferencing locks that * have already been freed. * Andy Walker (andy@lysaker.kvaerner.no), Sep 21, 1996. * * Made the block list a circular list to minimise searching in the list. * Andy Walker (andy@lysaker.kvaerner.no), Sep 25, 1996. * * Made mandatory locking a mount option. Default is not to allow mandatory * locking. * Andy Walker (andy@lysaker.kvaerner.no), Oct 04, 1996. * * Some adaptations for NFS support. * Olaf Kirch (okir@monad.swb.de), Dec 1996, * * Fixed /proc/locks interface so that we can't overrun the buffer we are handed. * Andy Walker (andy@lysaker.kvaerner.no), May 12, 1997. * * Use slab allocator instead of kmalloc/kfree. * Use generic list implementation from <linux/list.h>. * Sped up posix_locks_deadlock by only considering blocked locks. * Matthew Wilcox <willy@debian.org>, March, 2000. * * Leases and LOCK_MAND * Matthew Wilcox <willy@debian.org>, June, 2000. * Stephen Rothwell <sfr@canb.auug.org.au>, June, 2000. */ #include <linux/capability.h> #include <linux/file.h> |
9f3acc314
|
119 |
#include <linux/fdtable.h> |
1da177e4c
|
120 121 |
#include <linux/fs.h> #include <linux/init.h> |
1da177e4c
|
122 123 |
#include <linux/security.h> #include <linux/slab.h> |
1da177e4c
|
124 125 |
#include <linux/syscalls.h> #include <linux/time.h> |
4fb3a5386
|
126 |
#include <linux/rcupdate.h> |
ab1f16116
|
127 |
#include <linux/pid_namespace.h> |
48f741865
|
128 |
#include <linux/hashtable.h> |
7012b02a2
|
129 |
#include <linux/percpu.h> |
1da177e4c
|
130 |
|
62af4f1f7
|
131 132 |
#define CREATE_TRACE_POINTS #include <trace/events/filelock.h> |
7c0f6ba68
|
133 |
#include <linux/uaccess.h> |
1da177e4c
|
134 135 136 |
#define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) |
11afe9f76
|
137 |
#define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT)) |
cff2fce58
|
138 |
#define IS_OFDLCK(fl) (fl->fl_flags & FL_OFDLCK) |
9d5b86ac1
|
139 |
#define IS_REMOTELCK(fl) (fl->fl_pid <= 0) |
1da177e4c
|
140 |
|
c568d6834
|
141 142 |
static inline bool is_remote_lock(struct file *filp) { |
1751e8a6c
|
143 |
return likely(!(filp->f_path.dentry->d_sb->s_flags & SB_NOREMOTELOCK)); |
c568d6834
|
144 |
} |
ab83fa4b4
|
145 146 |
static bool lease_breaking(struct file_lock *fl) { |
778fc546f
|
147 148 149 150 151 152 153 154 155 156 |
return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING); } static int target_leasetype(struct file_lock *fl) { if (fl->fl_flags & FL_UNLOCK_PENDING) return F_UNLCK; if (fl->fl_flags & FL_DOWNGRADE_PENDING) return F_RDLCK; return fl->fl_type; |
ab83fa4b4
|
157 |
} |
1da177e4c
|
158 159 |
int leases_enable = 1; int lease_break_time = 45; |
1c8c601a8
|
160 |
/* |
7012b02a2
|
161 |
* The global file_lock_list is only used for displaying /proc/locks, so we |
7c3f654d8
|
162 163 164 165 166 |
* keep a list on each CPU, with each list protected by its own spinlock. * Global serialization is done using file_rwsem. * * Note that alterations to the list also require that the relevant flc_lock is * held. |
1c8c601a8
|
167 |
*/ |
7c3f654d8
|
168 169 170 171 172 |
struct file_lock_list_struct { spinlock_t lock; struct hlist_head hlist; }; static DEFINE_PER_CPU(struct file_lock_list_struct, file_lock_list); |
aba376607
|
173 |
DEFINE_STATIC_PERCPU_RWSEM(file_rwsem); |
889746917
|
174 |
|
1c8c601a8
|
175 |
/* |
48f741865
|
176 |
* The blocked_hash is used to find POSIX lock loops for deadlock detection. |
7b2296afb
|
177 |
* It is protected by blocked_lock_lock. |
48f741865
|
178 179 180 181 182 183 184 |
* * We hash locks by lockowner in order to optimize searching for the lock a * particular lockowner is waiting on. * * FIXME: make this value scale via some heuristic? We generally will want more * buckets when we have more lockowners holding locks, but that's a little * difficult to determine without knowing what the workload will look like. |
1c8c601a8
|
185 |
*/ |
48f741865
|
186 187 |
#define BLOCKED_HASH_BITS 7 static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS); |
889746917
|
188 |
|
1c8c601a8
|
189 |
/* |
7b2296afb
|
190 191 |
* This lock protects the blocked_hash. Generally, if you're accessing it, you * want to be holding this lock. |
1c8c601a8
|
192 193 194 195 196 197 |
* * In addition, it also protects the fl->fl_block list, and the fl->fl_next * pointer for file_lock structures that are acting as lock requests (in * contrast to those that are acting as records of acquired locks). * * Note that when we acquire this lock in order to change the above fields, |
6109c8503
|
198 |
* we often hold the flc_lock as well. In certain cases, when reading the fields |
1c8c601a8
|
199 |
* protected by this lock, we can skip acquiring it iff we already hold the |
6109c8503
|
200 |
* flc_lock. |
1c8c601a8
|
201 202 |
* * In particular, adding an entry to the fl_block list requires that you hold |
6109c8503
|
203 204 |
* both the flc_lock and the blocked_lock_lock (acquired in that order). * Deleting an entry from the list however only requires the file_lock_lock. |
1c8c601a8
|
205 |
*/ |
7b2296afb
|
206 |
static DEFINE_SPINLOCK(blocked_lock_lock); |
1da177e4c
|
207 |
|
4a075e39c
|
208 |
static struct kmem_cache *flctx_cache __read_mostly; |
e18b890bb
|
209 |
static struct kmem_cache *filelock_cache __read_mostly; |
1da177e4c
|
210 |
|
4a075e39c
|
211 |
static struct file_lock_context * |
5c1c669a1
|
212 |
locks_get_lock_context(struct inode *inode, int type) |
4a075e39c
|
213 |
{ |
128a37852
|
214 |
struct file_lock_context *ctx; |
4a075e39c
|
215 |
|
128a37852
|
216 217 218 |
/* paired with cmpxchg() below */ ctx = smp_load_acquire(&inode->i_flctx); if (likely(ctx) || type == F_UNLCK) |
4a075e39c
|
219 |
goto out; |
128a37852
|
220 221 |
ctx = kmem_cache_alloc(flctx_cache, GFP_KERNEL); if (!ctx) |
4a075e39c
|
222 |
goto out; |
128a37852
|
223 224 225 226 |
spin_lock_init(&ctx->flc_lock); INIT_LIST_HEAD(&ctx->flc_flock); INIT_LIST_HEAD(&ctx->flc_posix); INIT_LIST_HEAD(&ctx->flc_lease); |
4a075e39c
|
227 228 229 230 231 |
/* * Assign the pointer if it's not already assigned. If it is, then * free the context we just allocated. */ |
128a37852
|
232 233 234 235 |
if (cmpxchg(&inode->i_flctx, NULL, ctx)) { kmem_cache_free(flctx_cache, ctx); ctx = smp_load_acquire(&inode->i_flctx); } |
4a075e39c
|
236 |
out: |
1890910fd
|
237 |
trace_locks_get_lock_context(inode, type, ctx); |
128a37852
|
238 |
return ctx; |
4a075e39c
|
239 |
} |
e24dadab0
|
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
static void locks_dump_ctx_list(struct list_head *list, char *list_type) { struct file_lock *fl; list_for_each_entry(fl, list, fl_list) { pr_warn("%s: fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u ", list_type, fl->fl_owner, fl->fl_flags, fl->fl_type, fl->fl_pid); } } static void locks_check_ctx_lists(struct inode *inode) { struct file_lock_context *ctx = inode->i_flctx; if (unlikely(!list_empty(&ctx->flc_flock) || !list_empty(&ctx->flc_posix) || !list_empty(&ctx->flc_lease))) { pr_warn("Leaked locks on dev=0x%x:0x%x ino=0x%lx: ", MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), inode->i_ino); locks_dump_ctx_list(&ctx->flc_flock, "FLOCK"); locks_dump_ctx_list(&ctx->flc_posix, "POSIX"); locks_dump_ctx_list(&ctx->flc_lease, "LEASE"); } } |
3953704fd
|
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
static void locks_check_ctx_file_list(struct file *filp, struct list_head *list, char *list_type) { struct file_lock *fl; struct inode *inode = locks_inode(filp); list_for_each_entry(fl, list, fl_list) if (fl->fl_file == filp) pr_warn("Leaked %s lock on dev=0x%x:0x%x ino=0x%lx " " fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u ", list_type, MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), inode->i_ino, fl->fl_owner, fl->fl_flags, fl->fl_type, fl->fl_pid); } |
4a075e39c
|
284 |
void |
f27a0fe08
|
285 |
locks_free_lock_context(struct inode *inode) |
4a075e39c
|
286 |
{ |
f27a0fe08
|
287 |
struct file_lock_context *ctx = inode->i_flctx; |
e24dadab0
|
288 289 |
if (unlikely(ctx)) { locks_check_ctx_lists(inode); |
4a075e39c
|
290 291 292 |
kmem_cache_free(flctx_cache, ctx); } } |
ee19cc406
|
293 |
static void locks_init_lock_heads(struct file_lock *fl) |
a51cb91d8
|
294 |
{ |
139ca04ee
|
295 |
INIT_HLIST_NODE(&fl->fl_link); |
6dee60f69
|
296 |
INIT_LIST_HEAD(&fl->fl_list); |
ee19cc406
|
297 298 |
INIT_LIST_HEAD(&fl->fl_block); init_waitqueue_head(&fl->fl_wait); |
a51cb91d8
|
299 |
} |
1da177e4c
|
300 |
/* Allocate an empty lock structure. */ |
c5b1f0d92
|
301 |
struct file_lock *locks_alloc_lock(void) |
1da177e4c
|
302 |
{ |
ee19cc406
|
303 |
struct file_lock *fl = kmem_cache_zalloc(filelock_cache, GFP_KERNEL); |
a51cb91d8
|
304 305 |
if (fl) |
ee19cc406
|
306 |
locks_init_lock_heads(fl); |
a51cb91d8
|
307 308 |
return fl; |
1da177e4c
|
309 |
} |
c5b1f0d92
|
310 |
EXPORT_SYMBOL_GPL(locks_alloc_lock); |
1da177e4c
|
311 |
|
a9e61e25f
|
312 |
void locks_release_private(struct file_lock *fl) |
47831f35b
|
313 314 315 316 317 318 |
{ if (fl->fl_ops) { if (fl->fl_ops->fl_release_private) fl->fl_ops->fl_release_private(fl); fl->fl_ops = NULL; } |
47831f35b
|
319 |
|
5c97d7b14
|
320 |
if (fl->fl_lmops) { |
cae80b305
|
321 322 323 324 |
if (fl->fl_lmops->lm_put_owner) { fl->fl_lmops->lm_put_owner(fl->fl_owner); fl->fl_owner = NULL; } |
5c97d7b14
|
325 326 |
fl->fl_lmops = NULL; } |
47831f35b
|
327 |
} |
a9e61e25f
|
328 |
EXPORT_SYMBOL_GPL(locks_release_private); |
47831f35b
|
329 |
|
1da177e4c
|
330 |
/* Free a lock which is not in use. */ |
05fa3135f
|
331 |
void locks_free_lock(struct file_lock *fl) |
1da177e4c
|
332 |
{ |
5ce29646e
|
333 |
BUG_ON(waitqueue_active(&fl->fl_wait)); |
6dee60f69
|
334 |
BUG_ON(!list_empty(&fl->fl_list)); |
5ce29646e
|
335 |
BUG_ON(!list_empty(&fl->fl_block)); |
139ca04ee
|
336 |
BUG_ON(!hlist_unhashed(&fl->fl_link)); |
1da177e4c
|
337 |
|
47831f35b
|
338 |
locks_release_private(fl); |
1da177e4c
|
339 340 |
kmem_cache_free(filelock_cache, fl); } |
05fa3135f
|
341 |
EXPORT_SYMBOL(locks_free_lock); |
1da177e4c
|
342 |
|
ed9814d85
|
343 344 345 346 347 348 |
static void locks_dispose_list(struct list_head *dispose) { struct file_lock *fl; while (!list_empty(dispose)) { |
6dee60f69
|
349 350 |
fl = list_first_entry(dispose, struct file_lock, fl_list); list_del_init(&fl->fl_list); |
ed9814d85
|
351 352 353 |
locks_free_lock(fl); } } |
1da177e4c
|
354 355 |
void locks_init_lock(struct file_lock *fl) { |
ee19cc406
|
356 357 |
memset(fl, 0, sizeof(struct file_lock)); locks_init_lock_heads(fl); |
1da177e4c
|
358 359 360 |
} EXPORT_SYMBOL(locks_init_lock); |
1da177e4c
|
361 362 363 |
/* * Initialize a new lock from an existing file_lock structure. */ |
3fe0fff18
|
364 |
void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) |
1da177e4c
|
365 366 367 |
{ new->fl_owner = fl->fl_owner; new->fl_pid = fl->fl_pid; |
0996905f9
|
368 |
new->fl_file = NULL; |
1da177e4c
|
369 370 371 372 |
new->fl_flags = fl->fl_flags; new->fl_type = fl->fl_type; new->fl_start = fl->fl_start; new->fl_end = fl->fl_end; |
f328296e2
|
373 |
new->fl_lmops = fl->fl_lmops; |
0996905f9
|
374 |
new->fl_ops = NULL; |
f328296e2
|
375 376 377 |
if (fl->fl_lmops) { if (fl->fl_lmops->lm_get_owner) |
cae80b305
|
378 |
fl->fl_lmops->lm_get_owner(fl->fl_owner); |
f328296e2
|
379 |
} |
0996905f9
|
380 |
} |
3fe0fff18
|
381 |
EXPORT_SYMBOL(locks_copy_conflock); |
0996905f9
|
382 383 384 |
void locks_copy_lock(struct file_lock *new, struct file_lock *fl) { |
566709bd6
|
385 386 |
/* "new" must be a freshly-initialized lock */ WARN_ON_ONCE(new->fl_ops); |
0996905f9
|
387 |
|
3fe0fff18
|
388 |
locks_copy_conflock(new, fl); |
f328296e2
|
389 |
|
0996905f9
|
390 |
new->fl_file = fl->fl_file; |
1da177e4c
|
391 |
new->fl_ops = fl->fl_ops; |
47831f35b
|
392 |
|
f328296e2
|
393 394 395 396 |
if (fl->fl_ops) { if (fl->fl_ops->fl_copy_lock) fl->fl_ops->fl_copy_lock(new, fl); } |
1da177e4c
|
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
} EXPORT_SYMBOL(locks_copy_lock); static inline int flock_translate_cmd(int cmd) { if (cmd & LOCK_MAND) return cmd & (LOCK_MAND | LOCK_RW); switch (cmd) { case LOCK_SH: return F_RDLCK; case LOCK_EX: return F_WRLCK; case LOCK_UN: return F_UNLCK; } return -EINVAL; } /* Fill in a file_lock structure with an appropriate FLOCK lock. */ |
6e129d006
|
416 417 |
static struct file_lock * flock_make_lock(struct file *filp, unsigned int cmd) |
1da177e4c
|
418 419 420 |
{ struct file_lock *fl; int type = flock_translate_cmd(cmd); |
6e129d006
|
421 |
|
1da177e4c
|
422 |
if (type < 0) |
6e129d006
|
423 |
return ERR_PTR(type); |
1da177e4c
|
424 425 426 |
fl = locks_alloc_lock(); if (fl == NULL) |
6e129d006
|
427 |
return ERR_PTR(-ENOMEM); |
1da177e4c
|
428 429 |
fl->fl_file = filp; |
73a8f5f7e
|
430 |
fl->fl_owner = filp; |
1da177e4c
|
431 432 433 434 435 |
fl->fl_pid = current->tgid; fl->fl_flags = FL_FLOCK; fl->fl_type = type; fl->fl_end = OFFSET_MAX; |
6e129d006
|
436 |
return fl; |
1da177e4c
|
437 |
} |
0ec4f431e
|
438 |
static int assign_type(struct file_lock *fl, long type) |
1da177e4c
|
439 440 441 442 443 444 445 446 447 448 449 450 |
{ switch (type) { case F_RDLCK: case F_WRLCK: case F_UNLCK: fl->fl_type = type; break; default: return -EINVAL; } return 0; } |
ef12e72a0
|
451 452 |
static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, struct flock64 *l) |
1da177e4c
|
453 |
{ |
1da177e4c
|
454 |
switch (l->l_whence) { |
f5579f8c7
|
455 |
case SEEK_SET: |
ef12e72a0
|
456 |
fl->fl_start = 0; |
1da177e4c
|
457 |
break; |
f5579f8c7
|
458 |
case SEEK_CUR: |
ef12e72a0
|
459 |
fl->fl_start = filp->f_pos; |
1da177e4c
|
460 |
break; |
f5579f8c7
|
461 |
case SEEK_END: |
ef12e72a0
|
462 |
fl->fl_start = i_size_read(file_inode(filp)); |
1da177e4c
|
463 464 465 466 |
break; default: return -EINVAL; } |
ef12e72a0
|
467 468 469 470 471 |
if (l->l_start > OFFSET_MAX - fl->fl_start) return -EOVERFLOW; fl->fl_start += l->l_start; if (fl->fl_start < 0) return -EINVAL; |
1da177e4c
|
472 473 474 |
/* POSIX-1996 leaves the case l->l_len < 0 undefined; POSIX-2001 defines it. */ |
4c780a468
|
475 |
if (l->l_len > 0) { |
ef12e72a0
|
476 477 478 |
if (l->l_len - 1 > OFFSET_MAX - fl->fl_start) return -EOVERFLOW; fl->fl_end = fl->fl_start + l->l_len - 1; |
4c780a468
|
479 |
} else if (l->l_len < 0) { |
ef12e72a0
|
480 |
if (fl->fl_start + l->l_len < 0) |
4c780a468
|
481 |
return -EINVAL; |
ef12e72a0
|
482 483 484 485 |
fl->fl_end = fl->fl_start - 1; fl->fl_start += l->l_len; } else fl->fl_end = OFFSET_MAX; |
1da177e4c
|
486 487 488 489 490 491 492 493 494 |
fl->fl_owner = current->files; fl->fl_pid = current->tgid; fl->fl_file = filp; fl->fl_flags = FL_POSIX; fl->fl_ops = NULL; fl->fl_lmops = NULL; return assign_type(fl, l->l_type); } |
ef12e72a0
|
495 496 497 498 499 |
/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX * style lock. */ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, struct flock *l) |
1da177e4c
|
500 |
{ |
ef12e72a0
|
501 502 503 504 505 506 507 508 |
struct flock64 ll = { .l_type = l->l_type, .l_whence = l->l_whence, .l_start = l->l_start, .l_len = l->l_len, }; return flock64_to_posix_lock(filp, fl, &ll); |
1da177e4c
|
509 |
} |
1da177e4c
|
510 511 |
/* default lease lock manager operations */ |
4d01b7f5e
|
512 513 |
static bool lease_break_callback(struct file_lock *fl) |
1da177e4c
|
514 515 |
{ kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG); |
4d01b7f5e
|
516 |
return false; |
1da177e4c
|
517 |
} |
1c7dd2ff4
|
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
static void lease_setup(struct file_lock *fl, void **priv) { struct file *filp = fl->fl_file; struct fasync_struct *fa = *priv; /* * fasync_insert_entry() returns the old entry if any. If there was no * old entry, then it used "priv" and inserted it into the fasync list. * Clear the pointer to indicate that it shouldn't be freed. */ if (!fasync_insert_entry(fa->fa_fd, filp, &fl->fl_fasync, fa)) *priv = NULL; __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); } |
7b021967c
|
534 |
static const struct lock_manager_operations lease_manager_ops = { |
8fb47a4fb
|
535 |
.lm_break = lease_break_callback, |
8fb47a4fb
|
536 |
.lm_change = lease_modify, |
1c7dd2ff4
|
537 |
.lm_setup = lease_setup, |
1da177e4c
|
538 539 540 541 542 |
}; /* * Initialize a lease, use the default lock manager operations */ |
0ec4f431e
|
543 |
static int lease_init(struct file *filp, long type, struct file_lock *fl) |
447a5647c
|
544 |
{ |
75dff55af
|
545 546 |
if (assign_type(fl, type) != 0) return -EINVAL; |
7ca76311f
|
547 |
fl->fl_owner = filp; |
1da177e4c
|
548 549 550 551 |
fl->fl_pid = current->tgid; fl->fl_file = filp; fl->fl_flags = FL_LEASE; |
1da177e4c
|
552 553 554 555 556 557 558 559 |
fl->fl_start = 0; fl->fl_end = OFFSET_MAX; fl->fl_ops = NULL; fl->fl_lmops = &lease_manager_ops; return 0; } /* Allocate a file_lock initialised to this type of lease */ |
0ec4f431e
|
560 |
static struct file_lock *lease_alloc(struct file *filp, long type) |
1da177e4c
|
561 562 |
{ struct file_lock *fl = locks_alloc_lock(); |
75dff55af
|
563 |
int error = -ENOMEM; |
1da177e4c
|
564 565 |
if (fl == NULL) |
e32b8ee27
|
566 |
return ERR_PTR(error); |
1da177e4c
|
567 568 |
error = lease_init(filp, type, fl); |
75dff55af
|
569 570 |
if (error) { locks_free_lock(fl); |
e32b8ee27
|
571 |
return ERR_PTR(error); |
75dff55af
|
572 |
} |
e32b8ee27
|
573 |
return fl; |
1da177e4c
|
574 575 576 577 578 579 580 581 582 583 584 585 586 |
} /* Check if two locks overlap each other. */ static inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2) { return ((fl1->fl_end >= fl2->fl_start) && (fl2->fl_end >= fl1->fl_start)); } /* * Check whether two locks have the same owner. */ |
33443c42f
|
587 |
static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) |
1da177e4c
|
588 |
{ |
8fb47a4fb
|
589 |
if (fl1->fl_lmops && fl1->fl_lmops->lm_compare_owner) |
1da177e4c
|
590 |
return fl2->fl_lmops == fl1->fl_lmops && |
8fb47a4fb
|
591 |
fl1->fl_lmops->lm_compare_owner(fl1, fl2); |
1da177e4c
|
592 593 |
return fl1->fl_owner == fl2->fl_owner; } |
6109c8503
|
594 |
/* Must be called with the flc_lock held! */ |
6ca10ed8e
|
595 |
static void locks_insert_global_locks(struct file_lock *fl) |
889746917
|
596 |
{ |
7c3f654d8
|
597 |
struct file_lock_list_struct *fll = this_cpu_ptr(&file_lock_list); |
aba376607
|
598 |
percpu_rwsem_assert_held(&file_rwsem); |
7c3f654d8
|
599 |
spin_lock(&fll->lock); |
7012b02a2
|
600 |
fl->fl_link_cpu = smp_processor_id(); |
7c3f654d8
|
601 602 |
hlist_add_head(&fl->fl_link, &fll->hlist); spin_unlock(&fll->lock); |
889746917
|
603 |
} |
6109c8503
|
604 |
/* Must be called with the flc_lock held! */ |
6ca10ed8e
|
605 |
static void locks_delete_global_locks(struct file_lock *fl) |
889746917
|
606 |
{ |
7c3f654d8
|
607 |
struct file_lock_list_struct *fll; |
aba376607
|
608 |
percpu_rwsem_assert_held(&file_rwsem); |
7012b02a2
|
609 610 |
/* * Avoid taking lock if already unhashed. This is safe since this check |
6109c8503
|
611 |
* is done while holding the flc_lock, and new insertions into the list |
7012b02a2
|
612 613 614 615 |
* also require that it be held. */ if (hlist_unhashed(&fl->fl_link)) return; |
7c3f654d8
|
616 617 618 |
fll = per_cpu_ptr(&file_lock_list, fl->fl_link_cpu); spin_lock(&fll->lock); |
139ca04ee
|
619 |
hlist_del_init(&fl->fl_link); |
7c3f654d8
|
620 |
spin_unlock(&fll->lock); |
889746917
|
621 |
} |
3999e4936
|
622 623 624 625 626 627 628 |
static unsigned long posix_owner_key(struct file_lock *fl) { if (fl->fl_lmops && fl->fl_lmops->lm_owner_key) return fl->fl_lmops->lm_owner_key(fl); return (unsigned long)fl->fl_owner; } |
6ca10ed8e
|
629 |
static void locks_insert_global_blocked(struct file_lock *waiter) |
889746917
|
630 |
{ |
663d5af75
|
631 |
lockdep_assert_held(&blocked_lock_lock); |
3999e4936
|
632 |
hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter)); |
889746917
|
633 |
} |
6ca10ed8e
|
634 |
static void locks_delete_global_blocked(struct file_lock *waiter) |
889746917
|
635 |
{ |
663d5af75
|
636 |
lockdep_assert_held(&blocked_lock_lock); |
48f741865
|
637 |
hash_del(&waiter->fl_link); |
889746917
|
638 |
} |
1da177e4c
|
639 640 |
/* Remove waiter from blocker's block list. * When blocker ends up pointing to itself then the list is empty. |
1c8c601a8
|
641 |
* |
7b2296afb
|
642 |
* Must be called with blocked_lock_lock held. |
1da177e4c
|
643 |
*/ |
33443c42f
|
644 |
static void __locks_delete_block(struct file_lock *waiter) |
1da177e4c
|
645 |
{ |
889746917
|
646 |
locks_delete_global_blocked(waiter); |
1da177e4c
|
647 |
list_del_init(&waiter->fl_block); |
1da177e4c
|
648 649 |
waiter->fl_next = NULL; } |
1a9e64a71
|
650 |
static void locks_delete_block(struct file_lock *waiter) |
1da177e4c
|
651 |
{ |
7b2296afb
|
652 |
spin_lock(&blocked_lock_lock); |
1da177e4c
|
653 |
__locks_delete_block(waiter); |
7b2296afb
|
654 |
spin_unlock(&blocked_lock_lock); |
1da177e4c
|
655 656 657 658 659 660 |
} /* Insert waiter into blocker's block list. * We use a circular list so that processes can be easily woken up in * the order they blocked. The documentation doesn't require this but * it seems like the reasonable thing to do. |
1c8c601a8
|
661 |
* |
6109c8503
|
662 663 664 665 |
* Must be called with both the flc_lock and blocked_lock_lock held. The * fl_block list itself is protected by the blocked_lock_lock, but by ensuring * that the flc_lock is also held on insertions we can avoid taking the * blocked_lock_lock in some cases when we see that the fl_block list is empty. |
1da177e4c
|
666 |
*/ |
1c8c601a8
|
667 668 |
static void __locks_insert_block(struct file_lock *blocker, struct file_lock *waiter) |
1da177e4c
|
669 |
{ |
6dc0fe8f8
|
670 |
BUG_ON(!list_empty(&waiter->fl_block)); |
1da177e4c
|
671 |
waiter->fl_next = blocker; |
889746917
|
672 |
list_add_tail(&waiter->fl_block, &blocker->fl_block); |
cff2fce58
|
673 |
if (IS_POSIX(blocker) && !IS_OFDLCK(blocker)) |
1c8c601a8
|
674 675 |
locks_insert_global_blocked(waiter); } |
6109c8503
|
676 |
/* Must be called with flc_lock held. */ |
1c8c601a8
|
677 678 679 |
static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter) { |
7b2296afb
|
680 |
spin_lock(&blocked_lock_lock); |
1c8c601a8
|
681 |
__locks_insert_block(blocker, waiter); |
7b2296afb
|
682 |
spin_unlock(&blocked_lock_lock); |
1da177e4c
|
683 |
} |
1cb360125
|
684 685 686 |
/* * Wake up processes blocked waiting for blocker. * |
6109c8503
|
687 |
* Must be called with the inode->flc_lock held! |
1da177e4c
|
688 689 690 |
*/ static void locks_wake_up_blocks(struct file_lock *blocker) { |
4e8c765d3
|
691 692 |
/* * Avoid taking global lock if list is empty. This is safe since new |
6109c8503
|
693 694 695 |
* blocked requests are only added to the list under the flc_lock, and * the flc_lock is always held here. Note that removal from the fl_block * list does not require the flc_lock, so we must recheck list_empty() |
7b2296afb
|
696 |
* after acquiring the blocked_lock_lock. |
4e8c765d3
|
697 698 699 |
*/ if (list_empty(&blocker->fl_block)) return; |
7b2296afb
|
700 |
spin_lock(&blocked_lock_lock); |
1da177e4c
|
701 |
while (!list_empty(&blocker->fl_block)) { |
f0c1cd0ea
|
702 703 704 |
struct file_lock *waiter; waiter = list_first_entry(&blocker->fl_block, |
1da177e4c
|
705 706 |
struct file_lock, fl_block); __locks_delete_block(waiter); |
8fb47a4fb
|
707 708 |
if (waiter->fl_lmops && waiter->fl_lmops->lm_notify) waiter->fl_lmops->lm_notify(waiter); |
1da177e4c
|
709 710 711 |
else wake_up(&waiter->fl_wait); } |
7b2296afb
|
712 |
spin_unlock(&blocked_lock_lock); |
1da177e4c
|
713 |
} |
5263e31e4
|
714 |
static void |
e084c1bd4
|
715 |
locks_insert_lock_ctx(struct file_lock *fl, struct list_head *before) |
5263e31e4
|
716 |
{ |
5263e31e4
|
717 718 719 |
list_add_tail(&fl->fl_list, before); locks_insert_global_locks(fl); } |
8634b51f6
|
720 |
static void |
e084c1bd4
|
721 |
locks_unlink_lock_ctx(struct file_lock *fl) |
1da177e4c
|
722 |
{ |
889746917
|
723 |
locks_delete_global_locks(fl); |
8634b51f6
|
724 |
list_del_init(&fl->fl_list); |
1da177e4c
|
725 |
locks_wake_up_blocks(fl); |
24cbe7845
|
726 |
} |
8634b51f6
|
727 |
static void |
e084c1bd4
|
728 |
locks_delete_lock_ctx(struct file_lock *fl, struct list_head *dispose) |
24cbe7845
|
729 |
{ |
e084c1bd4
|
730 |
locks_unlink_lock_ctx(fl); |
ed9814d85
|
731 |
if (dispose) |
6dee60f69
|
732 |
list_add(&fl->fl_list, dispose); |
ed9814d85
|
733 734 |
else locks_free_lock(fl); |
1da177e4c
|
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 |
} /* Determine if lock sys_fl blocks lock caller_fl. Common functionality * checks for shared/exclusive status of overlapping locks. */ static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) { if (sys_fl->fl_type == F_WRLCK) return 1; if (caller_fl->fl_type == F_WRLCK) return 1; return 0; } /* Determine if lock sys_fl blocks lock caller_fl. POSIX specific * checking before calling the locks_conflict(). */ static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) { /* POSIX locks owned by the same process do not conflict with * each other. */ |
9b8c86956
|
757 |
if (posix_same_owner(caller_fl, sys_fl)) |
1da177e4c
|
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 |
return (0); /* Check whether they overlap */ if (!locks_overlap(caller_fl, sys_fl)) return 0; return (locks_conflict(caller_fl, sys_fl)); } /* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific * checking before calling the locks_conflict(). */ static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) { /* FLOCK locks referring to the same filp do not conflict with * each other. */ |
9b8c86956
|
775 |
if (caller_fl->fl_file == sys_fl->fl_file) |
1da177e4c
|
776 777 778 779 780 781 |
return (0); if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND)) return 0; return (locks_conflict(caller_fl, sys_fl)); } |
6d34ac199
|
782 |
void |
9d6a8c5c2
|
783 |
posix_test_lock(struct file *filp, struct file_lock *fl) |
1da177e4c
|
784 785 |
{ struct file_lock *cfl; |
bd61e0a9c
|
786 |
struct file_lock_context *ctx; |
c568d6834
|
787 |
struct inode *inode = locks_inode(filp); |
1da177e4c
|
788 |
|
128a37852
|
789 |
ctx = smp_load_acquire(&inode->i_flctx); |
bd61e0a9c
|
790 791 792 793 |
if (!ctx || list_empty_careful(&ctx->flc_posix)) { fl->fl_type = F_UNLCK; return; } |
6109c8503
|
794 |
spin_lock(&ctx->flc_lock); |
bd61e0a9c
|
795 796 797 |
list_for_each_entry(cfl, &ctx->flc_posix, fl_list) { if (posix_locks_conflict(fl, cfl)) { locks_copy_conflock(fl, cfl); |
bd61e0a9c
|
798 799 |
goto out; } |
1da177e4c
|
800 |
} |
bd61e0a9c
|
801 802 |
fl->fl_type = F_UNLCK; out: |
6109c8503
|
803 |
spin_unlock(&ctx->flc_lock); |
6d34ac199
|
804 |
return; |
1da177e4c
|
805 |
} |
1da177e4c
|
806 |
EXPORT_SYMBOL(posix_test_lock); |
b533184fc
|
807 808 809 810 811 |
/* * Deadlock detection: * * We attempt to detect deadlocks that are due purely to posix file * locks. |
1da177e4c
|
812 |
* |
b533184fc
|
813 814 815 816 817 818 819 |
* We assume that a task can be waiting for at most one lock at a time. * So for any acquired lock, the process holding that lock may be * waiting on at most one other lock. That lock in turns may be held by * someone waiting for at most one other lock. Given a requested lock * caller_fl which is about to wait for a conflicting lock block_fl, we * follow this chain of waiters to ensure we are not about to create a * cycle. |
1da177e4c
|
820 |
* |
b533184fc
|
821 822 823 |
* Since we do this before we ever put a process to sleep on a lock, we * are ensured that there is never a cycle; that is what guarantees that * the while() loop in posix_locks_deadlock() eventually completes. |
97855b49b
|
824 |
* |
b533184fc
|
825 826 827 |
* Note: the above assumption may not be true when handling lock * requests from a broken NFS client. It may also fail in the presence * of tasks (such as posix threads) sharing the same open file table. |
b533184fc
|
828 |
* To handle those cases, we just bail out after a few iterations. |
57b65325f
|
829 |
* |
cff2fce58
|
830 |
* For FL_OFDLCK locks, the owner is the filp, not the files_struct. |
57b65325f
|
831 832 833 834 |
* Because the owner is not even nominally tied to a thread of * execution, the deadlock detection below can't reasonably work well. Just * skip it for those. * |
cff2fce58
|
835 |
* In principle, we could do a more limited deadlock detection on FL_OFDLCK |
57b65325f
|
836 837 |
* locks that just checks for the case where two tasks are attempting to * upgrade from read to write locks on the same inode. |
1da177e4c
|
838 |
*/ |
97855b49b
|
839 840 |
#define MAX_DEADLK_ITERATIONS 10 |
b533184fc
|
841 842 843 844 |
/* Find a lock that the owner of the given block_fl is blocking on. */ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl) { struct file_lock *fl; |
3999e4936
|
845 |
hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) { |
b533184fc
|
846 847 848 849 850 |
if (posix_same_owner(fl, block_fl)) return fl->fl_next; } return NULL; } |
7b2296afb
|
851 |
/* Must be called with the blocked_lock_lock held! */ |
b0904e147
|
852 |
static int posix_locks_deadlock(struct file_lock *caller_fl, |
1da177e4c
|
853 854 |
struct file_lock *block_fl) { |
97855b49b
|
855 |
int i = 0; |
1da177e4c
|
856 |
|
663d5af75
|
857 |
lockdep_assert_held(&blocked_lock_lock); |
57b65325f
|
858 859 |
/* * This deadlock detector can't reasonably detect deadlocks with |
cff2fce58
|
860 |
* FL_OFDLCK locks, since they aren't owned by a process, per-se. |
57b65325f
|
861 |
*/ |
cff2fce58
|
862 |
if (IS_OFDLCK(caller_fl)) |
57b65325f
|
863 |
return 0; |
b533184fc
|
864 865 866 867 868 |
while ((block_fl = what_owner_is_waiting_for(block_fl))) { if (i++ > MAX_DEADLK_ITERATIONS) return 0; if (posix_same_owner(caller_fl, block_fl)) return 1; |
1da177e4c
|
869 870 871 |
} return 0; } |
1da177e4c
|
872 |
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks |
02888f41e
|
873 |
* after any leases, but before any posix locks. |
f475ae957
|
874 875 876 877 |
* * Note that if called with an FL_EXISTS argument, the caller may determine * whether or not a lock was successfully freed by testing the return * value for -ENOENT. |
1da177e4c
|
878 |
*/ |
bcd7f78d0
|
879 |
static int flock_lock_inode(struct inode *inode, struct file_lock *request) |
1da177e4c
|
880 |
{ |
993dfa877
|
881 |
struct file_lock *new_fl = NULL; |
5263e31e4
|
882 883 |
struct file_lock *fl; struct file_lock_context *ctx; |
1da177e4c
|
884 |
int error = 0; |
5263e31e4
|
885 |
bool found = false; |
ed9814d85
|
886 |
LIST_HEAD(dispose); |
1da177e4c
|
887 |
|
5c1c669a1
|
888 889 890 891 892 893 |
ctx = locks_get_lock_context(inode, request->fl_type); if (!ctx) { if (request->fl_type != F_UNLCK) return -ENOMEM; return (request->fl_flags & FL_EXISTS) ? -ENOENT : 0; } |
5263e31e4
|
894 |
|
b89f43213
|
895 |
if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { |
84d535ade
|
896 |
new_fl = locks_alloc_lock(); |
b89f43213
|
897 898 |
if (!new_fl) return -ENOMEM; |
84d535ade
|
899 |
} |
87709e28d
|
900 |
percpu_down_read_preempt_disable(&file_rwsem); |
6109c8503
|
901 |
spin_lock(&ctx->flc_lock); |
b89f43213
|
902 903 |
if (request->fl_flags & FL_ACCESS) goto find_conflict; |
5263e31e4
|
904 |
list_for_each_entry(fl, &ctx->flc_flock, fl_list) { |
bcd7f78d0
|
905 |
if (request->fl_file != fl->fl_file) |
1da177e4c
|
906 |
continue; |
993dfa877
|
907 |
if (request->fl_type == fl->fl_type) |
1da177e4c
|
908 |
goto out; |
5263e31e4
|
909 |
found = true; |
e084c1bd4
|
910 |
locks_delete_lock_ctx(fl, &dispose); |
1da177e4c
|
911 912 |
break; } |
1da177e4c
|
913 |
|
f475ae957
|
914 915 916 |
if (request->fl_type == F_UNLCK) { if ((request->fl_flags & FL_EXISTS) && !found) error = -ENOENT; |
993dfa877
|
917 |
goto out; |
f475ae957
|
918 |
} |
1da177e4c
|
919 |
|
f07f18dd6
|
920 |
find_conflict: |
5263e31e4
|
921 |
list_for_each_entry(fl, &ctx->flc_flock, fl_list) { |
993dfa877
|
922 |
if (!flock_locks_conflict(request, fl)) |
1da177e4c
|
923 924 |
continue; error = -EAGAIN; |
bde74e4bc
|
925 926 927 928 |
if (!(request->fl_flags & FL_SLEEP)) goto out; error = FILE_LOCK_DEFERRED; locks_insert_block(fl, request); |
1da177e4c
|
929 930 |
goto out; } |
f07f18dd6
|
931 932 |
if (request->fl_flags & FL_ACCESS) goto out; |
993dfa877
|
933 |
locks_copy_lock(new_fl, request); |
e084c1bd4
|
934 |
locks_insert_lock_ctx(new_fl, &ctx->flc_flock); |
993dfa877
|
935 |
new_fl = NULL; |
9cedc194a
|
936 |
error = 0; |
1da177e4c
|
937 938 |
out: |
6109c8503
|
939 |
spin_unlock(&ctx->flc_lock); |
87709e28d
|
940 |
percpu_up_read_preempt_enable(&file_rwsem); |
993dfa877
|
941 942 |
if (new_fl) locks_free_lock(new_fl); |
ed9814d85
|
943 |
locks_dispose_list(&dispose); |
1da177e4c
|
944 945 |
return error; } |
b4d629a39
|
946 947 |
static int posix_lock_inode(struct inode *inode, struct file_lock *request, struct file_lock *conflock) |
1da177e4c
|
948 |
{ |
bd61e0a9c
|
949 |
struct file_lock *fl, *tmp; |
39005d022
|
950 951 |
struct file_lock *new_fl = NULL; struct file_lock *new_fl2 = NULL; |
1da177e4c
|
952 953 |
struct file_lock *left = NULL; struct file_lock *right = NULL; |
bd61e0a9c
|
954 |
struct file_lock_context *ctx; |
b9746ef80
|
955 956 |
int error; bool added = false; |
ed9814d85
|
957 |
LIST_HEAD(dispose); |
1da177e4c
|
958 |
|
5c1c669a1
|
959 |
ctx = locks_get_lock_context(inode, request->fl_type); |
bd61e0a9c
|
960 |
if (!ctx) |
5c1c669a1
|
961 |
return (request->fl_type == F_UNLCK) ? 0 : -ENOMEM; |
bd61e0a9c
|
962 |
|
1da177e4c
|
963 964 965 |
/* * We may need two file_lock structures for this operation, * so we get them in advance to avoid races. |
39005d022
|
966 967 |
* * In some cases we can be sure, that no new locks will be needed |
1da177e4c
|
968 |
*/ |
39005d022
|
969 970 971 972 973 974 |
if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK || request->fl_start != 0 || request->fl_end != OFFSET_MAX)) { new_fl = locks_alloc_lock(); new_fl2 = locks_alloc_lock(); } |
1da177e4c
|
975 |
|
87709e28d
|
976 |
percpu_down_read_preempt_disable(&file_rwsem); |
6109c8503
|
977 |
spin_lock(&ctx->flc_lock); |
1cb360125
|
978 979 980 |
/* * New lock request. Walk all POSIX locks and look for conflicts. If * there are any, either return error or put the request on the |
48f741865
|
981 |
* blocker's list of waiters and the global blocked_hash. |
1cb360125
|
982 |
*/ |
1da177e4c
|
983 |
if (request->fl_type != F_UNLCK) { |
bd61e0a9c
|
984 |
list_for_each_entry(fl, &ctx->flc_posix, fl_list) { |
1da177e4c
|
985 986 |
if (!posix_locks_conflict(request, fl)) continue; |
5842add2f
|
987 |
if (conflock) |
3fe0fff18
|
988 |
locks_copy_conflock(conflock, fl); |
1da177e4c
|
989 990 991 |
error = -EAGAIN; if (!(request->fl_flags & FL_SLEEP)) goto out; |
1c8c601a8
|
992 993 994 995 |
/* * Deadlock detection and insertion into the blocked * locks list must be done while holding the same lock! */ |
1da177e4c
|
996 |
error = -EDEADLK; |
7b2296afb
|
997 |
spin_lock(&blocked_lock_lock); |
1c8c601a8
|
998 999 1000 1001 |
if (likely(!posix_locks_deadlock(request, fl))) { error = FILE_LOCK_DEFERRED; __locks_insert_block(fl, request); } |
7b2296afb
|
1002 |
spin_unlock(&blocked_lock_lock); |
1da177e4c
|
1003 1004 1005 1006 1007 1008 1009 1010 |
goto out; } } /* If we're just looking for a conflict, we're done. */ error = 0; if (request->fl_flags & FL_ACCESS) goto out; |
bd61e0a9c
|
1011 1012 1013 1014 |
/* Find the first old lock with the same owner as the new lock */ list_for_each_entry(fl, &ctx->flc_posix, fl_list) { if (posix_same_owner(request, fl)) break; |
1da177e4c
|
1015 |
} |
1cb360125
|
1016 |
/* Process locks with this owner. */ |
bd61e0a9c
|
1017 1018 1019 1020 1021 |
list_for_each_entry_safe_from(fl, tmp, &ctx->flc_posix, fl_list) { if (!posix_same_owner(request, fl)) break; /* Detect adjacent or overlapping regions (if same lock type) */ |
1da177e4c
|
1022 |
if (request->fl_type == fl->fl_type) { |
449231d6d
|
1023 1024 1025 1026 |
/* In all comparisons of start vs end, use * "start - 1" rather than "end + 1". If end * is OFFSET_MAX, end + 1 will become negative. */ |
1da177e4c
|
1027 |
if (fl->fl_end < request->fl_start - 1) |
bd61e0a9c
|
1028 |
continue; |
1da177e4c
|
1029 1030 1031 |
/* If the next lock in the list has entirely bigger * addresses than the new one, insert the lock here. */ |
449231d6d
|
1032 |
if (fl->fl_start - 1 > request->fl_end) |
1da177e4c
|
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 |
break; /* If we come here, the new and old lock are of the * same type and adjacent or overlapping. Make one * lock yielding from the lower start address of both * locks to the higher end address. */ if (fl->fl_start > request->fl_start) fl->fl_start = request->fl_start; else request->fl_start = fl->fl_start; if (fl->fl_end < request->fl_end) fl->fl_end = request->fl_end; else request->fl_end = fl->fl_end; if (added) { |
e084c1bd4
|
1049 |
locks_delete_lock_ctx(fl, &dispose); |
1da177e4c
|
1050 1051 1052 |
continue; } request = fl; |
b9746ef80
|
1053 |
added = true; |
bd61e0a9c
|
1054 |
} else { |
1da177e4c
|
1055 1056 1057 1058 |
/* Processing for different lock types is a bit * more complex. */ if (fl->fl_end < request->fl_start) |
bd61e0a9c
|
1059 |
continue; |
1da177e4c
|
1060 1061 1062 |
if (fl->fl_start > request->fl_end) break; if (request->fl_type == F_UNLCK) |
b9746ef80
|
1063 |
added = true; |
1da177e4c
|
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 |
if (fl->fl_start < request->fl_start) left = fl; /* If the next lock in the list has a higher end * address than the new one, insert the new one here. */ if (fl->fl_end > request->fl_end) { right = fl; break; } if (fl->fl_start >= request->fl_start) { /* The new lock completely replaces an old * one (This may happen several times). */ if (added) { |
e084c1bd4
|
1078 |
locks_delete_lock_ctx(fl, &dispose); |
1da177e4c
|
1079 1080 |
continue; } |
b84d49f94
|
1081 1082 1083 1084 1085 1086 |
/* * Replace the old lock with new_fl, and * remove the old one. It's safe to do the * insert here since we know that we won't be * using new_fl later, and that the lock is * just replacing an existing lock. |
1da177e4c
|
1087 |
*/ |
b84d49f94
|
1088 1089 1090 1091 1092 1093 |
error = -ENOLCK; if (!new_fl) goto out; locks_copy_lock(new_fl, request); request = new_fl; new_fl = NULL; |
e084c1bd4
|
1094 1095 |
locks_insert_lock_ctx(request, &fl->fl_list); locks_delete_lock_ctx(fl, &dispose); |
b9746ef80
|
1096 |
added = true; |
1da177e4c
|
1097 1098 |
} } |
1da177e4c
|
1099 |
} |
0d9a490ab
|
1100 |
/* |
1cb360125
|
1101 1102 1103 |
* The above code only modifies existing locks in case of merging or * replacing. If new lock(s) need to be inserted all modifications are * done below this, so it's safe yet to bail out. |
0d9a490ab
|
1104 1105 1106 1107 |
*/ error = -ENOLCK; /* "no luck" */ if (right && left == right && !new_fl2) goto out; |
1da177e4c
|
1108 1109 |
error = 0; if (!added) { |
f475ae957
|
1110 1111 1112 |
if (request->fl_type == F_UNLCK) { if (request->fl_flags & FL_EXISTS) error = -ENOENT; |
1da177e4c
|
1113 |
goto out; |
f475ae957
|
1114 |
} |
0d9a490ab
|
1115 1116 1117 1118 1119 |
if (!new_fl) { error = -ENOLCK; goto out; } |
1da177e4c
|
1120 |
locks_copy_lock(new_fl, request); |
e084c1bd4
|
1121 |
locks_insert_lock_ctx(new_fl, &fl->fl_list); |
2e2f756f8
|
1122 |
fl = new_fl; |
1da177e4c
|
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 |
new_fl = NULL; } if (right) { if (left == right) { /* The new lock breaks the old one in two pieces, * so we have to use the second new lock. */ left = new_fl2; new_fl2 = NULL; locks_copy_lock(left, right); |
e084c1bd4
|
1133 |
locks_insert_lock_ctx(left, &fl->fl_list); |
1da177e4c
|
1134 1135 1136 1137 1138 1139 1140 1141 1142 |
} right->fl_start = request->fl_end + 1; locks_wake_up_blocks(right); } if (left) { left->fl_end = request->fl_start - 1; locks_wake_up_blocks(left); } out: |
6109c8503
|
1143 |
spin_unlock(&ctx->flc_lock); |
87709e28d
|
1144 |
percpu_up_read_preempt_enable(&file_rwsem); |
1da177e4c
|
1145 1146 1147 1148 1149 1150 1151 |
/* * Free any unused locks. */ if (new_fl) locks_free_lock(new_fl); if (new_fl2) locks_free_lock(new_fl2); |
ed9814d85
|
1152 |
locks_dispose_list(&dispose); |
1890910fd
|
1153 |
trace_posix_lock_inode(inode, request, error); |
1da177e4c
|
1154 1155 1156 1157 1158 1159 1160 |
return error; } /** * posix_lock_file - Apply a POSIX-style lock to a file * @filp: The file to apply the lock to * @fl: The lock to be applied |
150b39345
|
1161 |
* @conflock: Place to return a copy of the conflicting lock, if found. |
1da177e4c
|
1162 1163 1164 1165 |
* * Add a POSIX style lock to a file. * We merge adjacent & overlapping locks whenever possible. * POSIX locks are sorted by owner task, then by starting address |
f475ae957
|
1166 1167 1168 1169 |
* * Note that if called with an FL_EXISTS argument, the caller may determine * whether or not a lock was successfully freed by testing the return * value for -ENOENT. |
1da177e4c
|
1170 |
*/ |
150b39345
|
1171 |
int posix_lock_file(struct file *filp, struct file_lock *fl, |
5842add2f
|
1172 1173 |
struct file_lock *conflock) { |
c568d6834
|
1174 |
return posix_lock_inode(locks_inode(filp), fl, conflock); |
1da177e4c
|
1175 |
} |
150b39345
|
1176 |
EXPORT_SYMBOL(posix_lock_file); |
1da177e4c
|
1177 1178 |
/** |
29d01b22e
|
1179 1180 |
* posix_lock_inode_wait - Apply a POSIX-style lock to a file * @inode: inode of file to which lock request should be applied |
1da177e4c
|
1181 1182 |
* @fl: The lock to be applied * |
616fb38fa
|
1183 |
* Apply a POSIX style lock request to an inode. |
1da177e4c
|
1184 |
*/ |
616fb38fa
|
1185 |
static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl) |
1da177e4c
|
1186 1187 1188 1189 |
{ int error; might_sleep (); for (;;) { |
b4d629a39
|
1190 |
error = posix_lock_inode(inode, fl, NULL); |
bde74e4bc
|
1191 |
if (error != FILE_LOCK_DEFERRED) |
1da177e4c
|
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 |
break; error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); if (!error) continue; locks_delete_block(fl); break; } return error; } |
29d01b22e
|
1202 |
|
9e8925b67
|
1203 |
#ifdef CONFIG_MANDATORY_FILE_LOCKING |
29d01b22e
|
1204 |
/** |
1da177e4c
|
1205 |
* locks_mandatory_locked - Check for an active lock |
d7a06983a
|
1206 |
* @file: the file to check |
1da177e4c
|
1207 1208 1209 1210 |
* * Searches the inode's list of locks to find any POSIX locks which conflict. * This function is called from locks_verify_locked() only. */ |
d7a06983a
|
1211 |
int locks_mandatory_locked(struct file *file) |
1da177e4c
|
1212 |
{ |
bd61e0a9c
|
1213 |
int ret; |
c568d6834
|
1214 |
struct inode *inode = locks_inode(file); |
bd61e0a9c
|
1215 |
struct file_lock_context *ctx; |
1da177e4c
|
1216 |
struct file_lock *fl; |
128a37852
|
1217 |
ctx = smp_load_acquire(&inode->i_flctx); |
bd61e0a9c
|
1218 1219 |
if (!ctx || list_empty_careful(&ctx->flc_posix)) return 0; |
1da177e4c
|
1220 1221 1222 |
/* * Search the lock list for this inode for any POSIX locks. */ |
6109c8503
|
1223 |
spin_lock(&ctx->flc_lock); |
bd61e0a9c
|
1224 1225 |
ret = 0; list_for_each_entry(fl, &ctx->flc_posix, fl_list) { |
73a8f5f7e
|
1226 |
if (fl->fl_owner != current->files && |
bd61e0a9c
|
1227 1228 |
fl->fl_owner != file) { ret = -EAGAIN; |
1da177e4c
|
1229 |
break; |
bd61e0a9c
|
1230 |
} |
1da177e4c
|
1231 |
} |
6109c8503
|
1232 |
spin_unlock(&ctx->flc_lock); |
bd61e0a9c
|
1233 |
return ret; |
1da177e4c
|
1234 1235 1236 1237 |
} /** * locks_mandatory_area - Check for a conflicting lock |
acc15575e
|
1238 |
* @inode: the file to check |
1da177e4c
|
1239 |
* @filp: how the file was opened (if it was) |
acc15575e
|
1240 1241 1242 |
* @start: first byte in the file to check * @end: lastbyte in the file to check * @type: %F_WRLCK for a write lock, else %F_RDLCK |
1da177e4c
|
1243 1244 |
* * Searches the inode's list of locks to find any POSIX locks which conflict. |
1da177e4c
|
1245 |
*/ |
acc15575e
|
1246 1247 |
int locks_mandatory_area(struct inode *inode, struct file *filp, loff_t start, loff_t end, unsigned char type) |
1da177e4c
|
1248 1249 1250 |
{ struct file_lock fl; int error; |
29723adee
|
1251 |
bool sleep = false; |
1da177e4c
|
1252 1253 |
locks_init_lock(&fl); |
1da177e4c
|
1254 1255 1256 1257 |
fl.fl_pid = current->tgid; fl.fl_file = filp; fl.fl_flags = FL_POSIX | FL_ACCESS; if (filp && !(filp->f_flags & O_NONBLOCK)) |
29723adee
|
1258 |
sleep = true; |
acc15575e
|
1259 1260 1261 |
fl.fl_type = type; fl.fl_start = start; fl.fl_end = end; |
1da177e4c
|
1262 1263 |
for (;;) { |
29723adee
|
1264 |
if (filp) { |
73a8f5f7e
|
1265 |
fl.fl_owner = filp; |
29723adee
|
1266 |
fl.fl_flags &= ~FL_SLEEP; |
b4d629a39
|
1267 |
error = posix_lock_inode(inode, &fl, NULL); |
29723adee
|
1268 1269 1270 1271 1272 1273 1274 |
if (!error) break; } if (sleep) fl.fl_flags |= FL_SLEEP; fl.fl_owner = current->files; |
b4d629a39
|
1275 |
error = posix_lock_inode(inode, &fl, NULL); |
bde74e4bc
|
1276 |
if (error != FILE_LOCK_DEFERRED) |
1da177e4c
|
1277 1278 1279 1280 1281 1282 1283 |
break; error = wait_event_interruptible(fl.fl_wait, !fl.fl_next); if (!error) { /* * If we've been sleeping someone might have * changed the permissions behind our back. */ |
a16877ca9
|
1284 |
if (__mandatory_lock(inode)) |
1da177e4c
|
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 |
continue; } locks_delete_block(&fl); break; } return error; } EXPORT_SYMBOL(locks_mandatory_area); |
9e8925b67
|
1296 |
#endif /* CONFIG_MANDATORY_FILE_LOCKING */ |
1da177e4c
|
1297 |
|
778fc546f
|
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 |
static void lease_clear_pending(struct file_lock *fl, int arg) { switch (arg) { case F_UNLCK: fl->fl_flags &= ~FL_UNLOCK_PENDING; /* fall through: */ case F_RDLCK: fl->fl_flags &= ~FL_DOWNGRADE_PENDING; } } |
1da177e4c
|
1308 |
/* We already had a lease on this file; just change its type */ |
7448cc37b
|
1309 |
int lease_modify(struct file_lock *fl, int arg, struct list_head *dispose) |
1da177e4c
|
1310 |
{ |
1da177e4c
|
1311 1312 1313 1314 |
int error = assign_type(fl, arg); if (error) return error; |
778fc546f
|
1315 |
lease_clear_pending(fl, arg); |
1da177e4c
|
1316 |
locks_wake_up_blocks(fl); |
3b6e2723f
|
1317 1318 1319 1320 1321 |
if (arg == F_UNLCK) { struct file *filp = fl->fl_file; f_delown(filp); filp->f_owner.signum = 0; |
96d6d59ce
|
1322 1323 1324 1325 1326 1327 |
fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync); if (fl->fl_fasync != NULL) { printk(KERN_ERR "locks_delete_lock: fasync == %p ", fl->fl_fasync); fl->fl_fasync = NULL; } |
e084c1bd4
|
1328 |
locks_delete_lock_ctx(fl, dispose); |
3b6e2723f
|
1329 |
} |
1da177e4c
|
1330 1331 |
return 0; } |
1da177e4c
|
1332 |
EXPORT_SYMBOL(lease_modify); |
778fc546f
|
1333 1334 1335 1336 1337 1338 1339 |
static bool past_time(unsigned long then) { if (!then) /* 0 is a special value meaning "this never expires": */ return false; return time_after(jiffies, then); } |
c45198eda
|
1340 |
static void time_out_leases(struct inode *inode, struct list_head *dispose) |
1da177e4c
|
1341 |
{ |
8634b51f6
|
1342 1343 |
struct file_lock_context *ctx = inode->i_flctx; struct file_lock *fl, *tmp; |
1da177e4c
|
1344 |
|
6109c8503
|
1345 |
lockdep_assert_held(&ctx->flc_lock); |
f82b4b678
|
1346 |
|
8634b51f6
|
1347 |
list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) { |
62af4f1f7
|
1348 |
trace_time_out_leases(inode, fl); |
778fc546f
|
1349 |
if (past_time(fl->fl_downgrade_time)) |
7448cc37b
|
1350 |
lease_modify(fl, F_RDLCK, dispose); |
778fc546f
|
1351 |
if (past_time(fl->fl_break_time)) |
7448cc37b
|
1352 |
lease_modify(fl, F_UNLCK, dispose); |
1da177e4c
|
1353 1354 |
} } |
df4e8d2c1
|
1355 1356 |
static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker) { |
11afe9f76
|
1357 1358 |
if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT)) return false; |
df4e8d2c1
|
1359 1360 1361 1362 |
if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) return false; return locks_conflict(breaker, lease); } |
03d12ddf8
|
1363 1364 1365 |
static bool any_leases_conflict(struct inode *inode, struct file_lock *breaker) { |
8634b51f6
|
1366 |
struct file_lock_context *ctx = inode->i_flctx; |
03d12ddf8
|
1367 |
struct file_lock *fl; |
6109c8503
|
1368 |
lockdep_assert_held(&ctx->flc_lock); |
03d12ddf8
|
1369 |
|
8634b51f6
|
1370 |
list_for_each_entry(fl, &ctx->flc_lease, fl_list) { |
03d12ddf8
|
1371 1372 1373 1374 1375 |
if (leases_conflict(fl, breaker)) return true; } return false; } |
1da177e4c
|
1376 1377 1378 |
/** * __break_lease - revoke all outstanding leases on file * @inode: the inode of the file to return |
df4e8d2c1
|
1379 1380 1381 1382 |
* @mode: O_RDONLY: break only write leases; O_WRONLY or O_RDWR: * break all leases * @type: FL_LEASE: break leases and delegations; FL_DELEG: break * only delegations |
1da177e4c
|
1383 |
* |
87250dd26
|
1384 1385 1386 |
* break_lease (inlined for speed) has checked there already is at least * some kind of lock (maybe a lease) on this file. Leases are broken on * a call to open() or truncate(). This function can sleep unless you |
1da177e4c
|
1387 1388 |
* specified %O_NONBLOCK to your open(). */ |
df4e8d2c1
|
1389 |
int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) |
1da177e4c
|
1390 |
{ |
778fc546f
|
1391 |
int error = 0; |
128a37852
|
1392 |
struct file_lock_context *ctx; |
a901125c6
|
1393 |
struct file_lock *new_fl, *fl, *tmp; |
1da177e4c
|
1394 |
unsigned long break_time; |
8737c9305
|
1395 |
int want_write = (mode & O_ACCMODE) != O_RDONLY; |
c45198eda
|
1396 |
LIST_HEAD(dispose); |
1da177e4c
|
1397 |
|
8737c9305
|
1398 |
new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); |
6d4b9e38d
|
1399 1400 |
if (IS_ERR(new_fl)) return PTR_ERR(new_fl); |
df4e8d2c1
|
1401 |
new_fl->fl_flags = type; |
1da177e4c
|
1402 |
|
8634b51f6
|
1403 |
/* typically we will check that ctx is non-NULL before calling */ |
128a37852
|
1404 |
ctx = smp_load_acquire(&inode->i_flctx); |
8634b51f6
|
1405 1406 1407 1408 |
if (!ctx) { WARN_ON_ONCE(1); return error; } |
87709e28d
|
1409 |
percpu_down_read_preempt_disable(&file_rwsem); |
6109c8503
|
1410 |
spin_lock(&ctx->flc_lock); |
1da177e4c
|
1411 |
|
c45198eda
|
1412 |
time_out_leases(inode, &dispose); |
1da177e4c
|
1413 |
|
03d12ddf8
|
1414 |
if (!any_leases_conflict(inode, new_fl)) |
778fc546f
|
1415 |
goto out; |
1da177e4c
|
1416 1417 1418 1419 1420 1421 |
break_time = 0; if (lease_break_time > 0) { break_time = jiffies + lease_break_time * HZ; if (break_time == 0) break_time++; /* so that 0 means no break time */ } |
a901125c6
|
1422 |
list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) { |
df4e8d2c1
|
1423 1424 |
if (!leases_conflict(fl, new_fl)) continue; |
778fc546f
|
1425 1426 1427 1428 |
if (want_write) { if (fl->fl_flags & FL_UNLOCK_PENDING) continue; fl->fl_flags |= FL_UNLOCK_PENDING; |
1da177e4c
|
1429 |
fl->fl_break_time = break_time; |
778fc546f
|
1430 |
} else { |
8634b51f6
|
1431 |
if (lease_breaking(fl)) |
778fc546f
|
1432 1433 1434 |
continue; fl->fl_flags |= FL_DOWNGRADE_PENDING; fl->fl_downgrade_time = break_time; |
1da177e4c
|
1435 |
} |
4d01b7f5e
|
1436 |
if (fl->fl_lmops->lm_break(fl)) |
e084c1bd4
|
1437 |
locks_delete_lock_ctx(fl, &dispose); |
1da177e4c
|
1438 |
} |
8634b51f6
|
1439 |
if (list_empty(&ctx->flc_lease)) |
4d01b7f5e
|
1440 |
goto out; |
843c6b2f4
|
1441 |
if (mode & O_NONBLOCK) { |
62af4f1f7
|
1442 |
trace_break_lease_noblock(inode, new_fl); |
1da177e4c
|
1443 1444 1445 1446 1447 |
error = -EWOULDBLOCK; goto out; } restart: |
8634b51f6
|
1448 1449 |
fl = list_first_entry(&ctx->flc_lease, struct file_lock, fl_list); break_time = fl->fl_break_time; |
f1c6bb2cb
|
1450 |
if (break_time != 0) |
1da177e4c
|
1451 |
break_time -= jiffies; |
f1c6bb2cb
|
1452 1453 |
if (break_time == 0) break_time++; |
8634b51f6
|
1454 |
locks_insert_block(fl, new_fl); |
62af4f1f7
|
1455 |
trace_break_lease_block(inode, new_fl); |
6109c8503
|
1456 |
spin_unlock(&ctx->flc_lock); |
87709e28d
|
1457 |
percpu_up_read_preempt_enable(&file_rwsem); |
aba376607
|
1458 |
|
c45198eda
|
1459 |
locks_dispose_list(&dispose); |
4321e01e7
|
1460 1461 |
error = wait_event_interruptible_timeout(new_fl->fl_wait, !new_fl->fl_next, break_time); |
aba376607
|
1462 |
|
87709e28d
|
1463 |
percpu_down_read_preempt_disable(&file_rwsem); |
6109c8503
|
1464 |
spin_lock(&ctx->flc_lock); |
62af4f1f7
|
1465 |
trace_break_lease_unblock(inode, new_fl); |
1c8c601a8
|
1466 |
locks_delete_block(new_fl); |
1da177e4c
|
1467 |
if (error >= 0) { |
778fc546f
|
1468 1469 1470 1471 |
/* * Wait for the next conflicting lease that has not been * broken yet */ |
03d12ddf8
|
1472 1473 1474 1475 |
if (error == 0) time_out_leases(inode, &dispose); if (any_leases_conflict(inode, new_fl)) goto restart; |
1da177e4c
|
1476 1477 |
error = 0; } |
1da177e4c
|
1478 |
out: |
6109c8503
|
1479 |
spin_unlock(&ctx->flc_lock); |
87709e28d
|
1480 |
percpu_up_read_preempt_enable(&file_rwsem); |
c45198eda
|
1481 |
locks_dispose_list(&dispose); |
6d4b9e38d
|
1482 |
locks_free_lock(new_fl); |
1da177e4c
|
1483 1484 1485 1486 1487 1488 |
return error; } EXPORT_SYMBOL(__break_lease); /** |
76c479480
|
1489 |
* lease_get_mtime - update modified time of an inode with exclusive lease |
1da177e4c
|
1490 |
* @inode: the inode |
76c479480
|
1491 |
* @time: pointer to a timespec which contains the last modified time |
1da177e4c
|
1492 1493 1494 |
* * This is to force NFS clients to flush their caches for files with * exclusive leases. The justification is that if someone has an |
a6b91919e
|
1495 |
* exclusive lease, then they could be modifying it. |
1da177e4c
|
1496 1497 1498 |
*/ void lease_get_mtime(struct inode *inode, struct timespec *time) { |
bfe860243
|
1499 |
bool has_lease = false; |
128a37852
|
1500 |
struct file_lock_context *ctx; |
8634b51f6
|
1501 |
struct file_lock *fl; |
bfe860243
|
1502 |
|
128a37852
|
1503 |
ctx = smp_load_acquire(&inode->i_flctx); |
8634b51f6
|
1504 |
if (ctx && !list_empty_careful(&ctx->flc_lease)) { |
6109c8503
|
1505 |
spin_lock(&ctx->flc_lock); |
8ace5dfb9
|
1506 1507 1508 1509 |
fl = list_first_entry_or_null(&ctx->flc_lease, struct file_lock, fl_list); if (fl && (fl->fl_type == F_WRLCK)) has_lease = true; |
6109c8503
|
1510 |
spin_unlock(&ctx->flc_lock); |
bfe860243
|
1511 1512 1513 |
} if (has_lease) |
c2050a454
|
1514 |
*time = current_time(inode); |
1da177e4c
|
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 |
} EXPORT_SYMBOL(lease_get_mtime); /** * fcntl_getlease - Enquire what lease is currently active * @filp: the file * * The value returned by this function will be one of * (if no lease break is pending): * * %F_RDLCK to indicate a shared lease is held. * * %F_WRLCK to indicate an exclusive lease is held. * * %F_UNLCK to indicate no lease is held. * * (if a lease break is pending): * * %F_RDLCK to indicate an exclusive lease needs to be * changed to a shared lease (or removed). * * %F_UNLCK to indicate the lease needs to be removed. * * XXX: sfr & willy disagree over whether F_INPROGRESS * should be returned to userspace. */ int fcntl_getlease(struct file *filp) { struct file_lock *fl; |
c568d6834
|
1545 |
struct inode *inode = locks_inode(filp); |
128a37852
|
1546 |
struct file_lock_context *ctx; |
1da177e4c
|
1547 |
int type = F_UNLCK; |
c45198eda
|
1548 |
LIST_HEAD(dispose); |
1da177e4c
|
1549 |
|
128a37852
|
1550 |
ctx = smp_load_acquire(&inode->i_flctx); |
8634b51f6
|
1551 |
if (ctx && !list_empty_careful(&ctx->flc_lease)) { |
5f43086bb
|
1552 |
percpu_down_read_preempt_disable(&file_rwsem); |
6109c8503
|
1553 |
spin_lock(&ctx->flc_lock); |
c568d6834
|
1554 |
time_out_leases(inode, &dispose); |
8634b51f6
|
1555 1556 1557 |
list_for_each_entry(fl, &ctx->flc_lease, fl_list) { if (fl->fl_file != filp) continue; |
778fc546f
|
1558 |
type = target_leasetype(fl); |
1da177e4c
|
1559 1560 |
break; } |
6109c8503
|
1561 |
spin_unlock(&ctx->flc_lock); |
5f43086bb
|
1562 |
percpu_up_read_preempt_enable(&file_rwsem); |
8634b51f6
|
1563 |
locks_dispose_list(&dispose); |
1da177e4c
|
1564 |
} |
1da177e4c
|
1565 1566 |
return type; } |
24cbe7845
|
1567 1568 1569 1570 1571 1572 |
/** * check_conflicting_open - see if the given dentry points to a file that has * an existing open that would conflict with the * desired lease. * @dentry: dentry to check * @arg: type of lease that we're trying to acquire |
7fadc59cc
|
1573 |
* @flags: current lock flags |
24cbe7845
|
1574 1575 1576 1577 1578 |
* * Check to see if there's an existing open fd on this file that would * conflict with the lease we're trying to set. */ static int |
11afe9f76
|
1579 |
check_conflicting_open(const struct dentry *dentry, const long arg, int flags) |
24cbe7845
|
1580 1581 1582 |
{ int ret = 0; struct inode *inode = dentry->d_inode; |
11afe9f76
|
1583 1584 |
if (flags & FL_LAYOUT) return 0; |
4d0c5ba2f
|
1585 1586 |
if ((arg == F_RDLCK) && (atomic_read(&d_real_inode(dentry)->i_writecount) > 0)) |
24cbe7845
|
1587 1588 1589 1590 1591 1592 1593 1594 |
return -EAGAIN; if ((arg == F_WRLCK) && ((d_count(dentry) > 1) || (atomic_read(&inode->i_count) > 1))) ret = -EAGAIN; return ret; } |
e6f5c7893
|
1595 1596 |
static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv) |
1da177e4c
|
1597 |
{ |
8634b51f6
|
1598 |
struct file_lock *fl, *my_fl = NULL, *lease; |
0f7fc9e4d
|
1599 |
struct dentry *dentry = filp->f_path.dentry; |
c568d6834
|
1600 |
struct inode *inode = dentry->d_inode; |
8634b51f6
|
1601 |
struct file_lock_context *ctx; |
df4e8d2c1
|
1602 |
bool is_deleg = (*flp)->fl_flags & FL_DELEG; |
c1f24ef4e
|
1603 |
int error; |
c45198eda
|
1604 |
LIST_HEAD(dispose); |
1da177e4c
|
1605 |
|
096657b65
|
1606 |
lease = *flp; |
62af4f1f7
|
1607 |
trace_generic_add_lease(inode, lease); |
5c1c669a1
|
1608 1609 |
/* Note that arg is never F_UNLCK here */ ctx = locks_get_lock_context(inode, arg); |
8634b51f6
|
1610 1611 |
if (!ctx) return -ENOMEM; |
df4e8d2c1
|
1612 1613 1614 1615 1616 1617 1618 1619 |
/* * In the delegation case we need mutual exclusion with * a number of operations that take the i_mutex. We trylock * because delegations are an optional optimization, and if * there's some chance of a conflict--we'd rather not * bother, maybe that's a sign this just isn't a good file to * hand out a delegation on. */ |
5955102c9
|
1620 |
if (is_deleg && !inode_trylock(inode)) |
df4e8d2c1
|
1621 1622 1623 1624 |
return -EAGAIN; if (is_deleg && arg == F_WRLCK) { /* Write delegations are not currently supported: */ |
5955102c9
|
1625 |
inode_unlock(inode); |
df4e8d2c1
|
1626 1627 1628 |
WARN_ON_ONCE(1); return -EINVAL; } |
096657b65
|
1629 |
|
87709e28d
|
1630 |
percpu_down_read_preempt_disable(&file_rwsem); |
6109c8503
|
1631 |
spin_lock(&ctx->flc_lock); |
c45198eda
|
1632 |
time_out_leases(inode, &dispose); |
11afe9f76
|
1633 |
error = check_conflicting_open(dentry, arg, lease->fl_flags); |
24cbe7845
|
1634 |
if (error) |
096657b65
|
1635 |
goto out; |
6d5e8b05c
|
1636 |
|
1da177e4c
|
1637 1638 1639 1640 1641 1642 1643 1644 |
/* * At this point, we know that if there is an exclusive * lease on this file, then we hold it on this filp * (otherwise our open of this file would have blocked). * And if we are trying to acquire an exclusive lease, * then the file is not open by anyone (including us) * except for this filp. */ |
c1f24ef4e
|
1645 |
error = -EAGAIN; |
8634b51f6
|
1646 |
list_for_each_entry(fl, &ctx->flc_lease, fl_list) { |
2ab99ee12
|
1647 1648 |
if (fl->fl_file == filp && fl->fl_owner == lease->fl_owner) { |
8634b51f6
|
1649 |
my_fl = fl; |
c1f24ef4e
|
1650 1651 |
continue; } |
8634b51f6
|
1652 |
|
c1f24ef4e
|
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 |
/* * No exclusive leases if someone else has a lease on * this file: */ if (arg == F_WRLCK) goto out; /* * Modifying our existing lease is OK, but no getting a * new lease if someone else is opening for write: */ if (fl->fl_flags & FL_UNLOCK_PENDING) goto out; |
1da177e4c
|
1665 |
} |
8634b51f6
|
1666 |
if (my_fl != NULL) { |
0164bf023
|
1667 1668 |
lease = my_fl; error = lease->fl_lmops->lm_change(lease, arg, &dispose); |
1c7dd2ff4
|
1669 1670 1671 |
if (error) goto out; goto out_setup; |
1da177e4c
|
1672 |
} |
1da177e4c
|
1673 1674 1675 |
error = -EINVAL; if (!leases_enable) goto out; |
e084c1bd4
|
1676 |
locks_insert_lock_ctx(lease, &ctx->flc_lease); |
24cbe7845
|
1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 |
/* * The check in break_lease() is lockless. It's possible for another * open to race in after we did the earlier check for a conflicting * open but before the lease was inserted. Check again for a * conflicting open and cancel the lease if there is one. * * We also add a barrier here to ensure that the insertion of the lock * precedes these checks. */ smp_mb(); |
11afe9f76
|
1687 |
error = check_conflicting_open(dentry, arg, lease->fl_flags); |
8634b51f6
|
1688 |
if (error) { |
e084c1bd4
|
1689 |
locks_unlink_lock_ctx(lease); |
8634b51f6
|
1690 1691 |
goto out; } |
1c7dd2ff4
|
1692 1693 1694 1695 |
out_setup: if (lease->fl_lmops->lm_setup) lease->fl_lmops->lm_setup(lease, priv); |
1da177e4c
|
1696 |
out: |
6109c8503
|
1697 |
spin_unlock(&ctx->flc_lock); |
87709e28d
|
1698 |
percpu_up_read_preempt_enable(&file_rwsem); |
c45198eda
|
1699 |
locks_dispose_list(&dispose); |
df4e8d2c1
|
1700 |
if (is_deleg) |
5955102c9
|
1701 |
inode_unlock(inode); |
8634b51f6
|
1702 |
if (!error && !my_fl) |
1c7dd2ff4
|
1703 |
*flp = NULL; |
1da177e4c
|
1704 1705 |
return error; } |
8335ebd94
|
1706 |
|
2ab99ee12
|
1707 |
static int generic_delete_lease(struct file *filp, void *owner) |
8335ebd94
|
1708 |
{ |
0efaa7e82
|
1709 |
int error = -EAGAIN; |
8634b51f6
|
1710 |
struct file_lock *fl, *victim = NULL; |
c568d6834
|
1711 |
struct inode *inode = locks_inode(filp); |
128a37852
|
1712 |
struct file_lock_context *ctx; |
c45198eda
|
1713 |
LIST_HEAD(dispose); |
8335ebd94
|
1714 |
|
128a37852
|
1715 |
ctx = smp_load_acquire(&inode->i_flctx); |
8634b51f6
|
1716 1717 1718 1719 |
if (!ctx) { trace_generic_delete_lease(inode, NULL); return error; } |
87709e28d
|
1720 |
percpu_down_read_preempt_disable(&file_rwsem); |
6109c8503
|
1721 |
spin_lock(&ctx->flc_lock); |
8634b51f6
|
1722 |
list_for_each_entry(fl, &ctx->flc_lease, fl_list) { |
2ab99ee12
|
1723 1724 |
if (fl->fl_file == filp && fl->fl_owner == owner) { |
8634b51f6
|
1725 |
victim = fl; |
0efaa7e82
|
1726 |
break; |
8634b51f6
|
1727 |
} |
8335ebd94
|
1728 |
} |
a9b1b455c
|
1729 |
trace_generic_delete_lease(inode, victim); |
8634b51f6
|
1730 |
if (victim) |
7448cc37b
|
1731 |
error = fl->fl_lmops->lm_change(victim, F_UNLCK, &dispose); |
6109c8503
|
1732 |
spin_unlock(&ctx->flc_lock); |
87709e28d
|
1733 |
percpu_up_read_preempt_enable(&file_rwsem); |
c45198eda
|
1734 |
locks_dispose_list(&dispose); |
0efaa7e82
|
1735 |
return error; |
8335ebd94
|
1736 1737 1738 1739 |
} /** * generic_setlease - sets a lease on an open file |
1c7dd2ff4
|
1740 1741 1742 1743 1744 |
* @filp: file pointer * @arg: type of lease to obtain * @flp: input - file_lock to use, output - file_lock inserted * @priv: private data for lm_setup (may be NULL if lm_setup * doesn't require it) |
8335ebd94
|
1745 1746 1747 |
* * The (input) flp->fl_lmops->lm_break function is required * by break_lease(). |
8335ebd94
|
1748 |
*/ |
e6f5c7893
|
1749 1750 |
int generic_setlease(struct file *filp, long arg, struct file_lock **flp, void **priv) |
8335ebd94
|
1751 |
{ |
c568d6834
|
1752 |
struct inode *inode = locks_inode(filp); |
8335ebd94
|
1753 |
int error; |
8e96e3b7b
|
1754 |
if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE)) |
8335ebd94
|
1755 1756 1757 1758 1759 1760 |
return -EACCES; if (!S_ISREG(inode->i_mode)) return -EINVAL; error = security_file_lock(filp, arg); if (error) return error; |
8335ebd94
|
1761 1762 |
switch (arg) { case F_UNLCK: |
2ab99ee12
|
1763 |
return generic_delete_lease(filp, *priv); |
8335ebd94
|
1764 1765 |
case F_RDLCK: case F_WRLCK: |
0efaa7e82
|
1766 1767 1768 1769 |
if (!(*flp)->fl_lmops->lm_break) { WARN_ON_ONCE(1); return -ENOLCK; } |
11afe9f76
|
1770 |
|
e6f5c7893
|
1771 |
return generic_add_lease(filp, arg, flp, priv); |
8335ebd94
|
1772 |
default: |
8d657eb3b
|
1773 |
return -EINVAL; |
8335ebd94
|
1774 1775 |
} } |
0af1a4504
|
1776 |
EXPORT_SYMBOL(generic_setlease); |
1da177e4c
|
1777 |
|
b89f43213
|
1778 |
/** |
e51673aa5
|
1779 |
* vfs_setlease - sets a lease on an open file |
1c7dd2ff4
|
1780 1781 1782 1783 1784 |
* @filp: file pointer * @arg: type of lease to obtain * @lease: file_lock to use when adding a lease * @priv: private info for lm_setup when adding a lease (may be * NULL if lm_setup doesn't require it) |
e51673aa5
|
1785 1786 1787 |
* * Call this to establish a lease on the file. The "lease" argument is not * used for F_UNLCK requests and may be NULL. For commands that set or alter |
80b79dd0e
|
1788 1789 |
* an existing lease, the ``(*lease)->fl_lmops->lm_break`` operation must be * set; if not, this function will return -ENOLCK (and generate a scary-looking |
e51673aa5
|
1790 |
* stack trace). |
1c7dd2ff4
|
1791 1792 1793 |
* * The "priv" pointer is passed directly to the lm_setup function as-is. It * may be NULL if the lm_setup operation doesn't require it. |
1da177e4c
|
1794 |
*/ |
e6f5c7893
|
1795 1796 |
int vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) |
1da177e4c
|
1797 |
{ |
c568d6834
|
1798 |
if (filp->f_op->setlease && is_remote_lock(filp)) |
f82b4b678
|
1799 |
return filp->f_op->setlease(filp, arg, lease, priv); |
1c7dd2ff4
|
1800 |
else |
f82b4b678
|
1801 |
return generic_setlease(filp, arg, lease, priv); |
1da177e4c
|
1802 |
} |
a9933cea7
|
1803 |
EXPORT_SYMBOL_GPL(vfs_setlease); |
1da177e4c
|
1804 |
|
0ceaf6c70
|
1805 |
static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) |
1da177e4c
|
1806 |
{ |
1c7dd2ff4
|
1807 |
struct file_lock *fl; |
f7347ce4e
|
1808 |
struct fasync_struct *new; |
1da177e4c
|
1809 |
int error; |
c5b1f0d92
|
1810 1811 1812 |
fl = lease_alloc(filp, arg); if (IS_ERR(fl)) return PTR_ERR(fl); |
1da177e4c
|
1813 |
|
f7347ce4e
|
1814 1815 1816 1817 1818 |
new = fasync_alloc(); if (!new) { locks_free_lock(fl); return -ENOMEM; } |
1c7dd2ff4
|
1819 |
new->fa_fd = fd; |
f7347ce4e
|
1820 |
|
1c7dd2ff4
|
1821 |
error = vfs_setlease(filp, arg, &fl, (void **)&new); |
2dfb928f7
|
1822 1823 |
if (fl) locks_free_lock(fl); |
f7347ce4e
|
1824 1825 |
if (new) fasync_free(new); |
1da177e4c
|
1826 1827 1828 1829 |
return error; } /** |
0ceaf6c70
|
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 |
* fcntl_setlease - sets a lease on an open file * @fd: open file descriptor * @filp: file pointer * @arg: type of lease to obtain * * Call this fcntl to establish a lease on the file. * Note that you also need to call %F_SETSIG to * receive a signal when the lease is broken. */ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) { if (arg == F_UNLCK) |
2ab99ee12
|
1842 |
return vfs_setlease(filp, F_UNLCK, NULL, (void **)&filp); |
0ceaf6c70
|
1843 1844 1845 1846 |
return do_fcntl_add_lease(fd, filp, arg); } /** |
29d01b22e
|
1847 1848 |
* flock_lock_inode_wait - Apply a FLOCK-style lock to a file * @inode: inode of the file to apply to |
1da177e4c
|
1849 1850 |
* @fl: The lock to be applied * |
29d01b22e
|
1851 |
* Apply a FLOCK style lock request to an inode. |
1da177e4c
|
1852 |
*/ |
616fb38fa
|
1853 |
static int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl) |
1da177e4c
|
1854 1855 1856 1857 |
{ int error; might_sleep(); for (;;) { |
29d01b22e
|
1858 |
error = flock_lock_inode(inode, fl); |
bde74e4bc
|
1859 |
if (error != FILE_LOCK_DEFERRED) |
1da177e4c
|
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 |
break; error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); if (!error) continue; locks_delete_block(fl); break; } return error; } |
29d01b22e
|
1870 |
/** |
e55c34a66
|
1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 |
* locks_lock_inode_wait - Apply a lock to an inode * @inode: inode of the file to apply to * @fl: The lock to be applied * * Apply a POSIX or FLOCK style lock request to an inode. */ int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl) { int res = 0; switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { case FL_POSIX: res = posix_lock_inode_wait(inode, fl); break; case FL_FLOCK: res = flock_lock_inode_wait(inode, fl); break; default: BUG(); } return res; } EXPORT_SYMBOL(locks_lock_inode_wait); /** |
1da177e4c
|
1895 1896 1897 1898 1899 |
* sys_flock: - flock() system call. * @fd: the file descriptor to lock. * @cmd: the type of lock to apply. * * Apply a %FL_FLOCK style lock to an open file descriptor. |
80b79dd0e
|
1900 |
* The @cmd can be one of: |
1da177e4c
|
1901 |
* |
80b79dd0e
|
1902 1903 1904 1905 1906 |
* - %LOCK_SH -- a shared lock. * - %LOCK_EX -- an exclusive lock. * - %LOCK_UN -- remove an existing lock. * - %LOCK_MAND -- a 'mandatory' flock. * This exists to emulate Windows Share Modes. |
1da177e4c
|
1907 1908 1909 1910 |
* * %LOCK_MAND can be combined with %LOCK_READ or %LOCK_WRITE to allow other * processes read and write access respectively. */ |
002c8976e
|
1911 |
SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) |
1da177e4c
|
1912 |
{ |
2903ff019
|
1913 |
struct fd f = fdget(fd); |
1da177e4c
|
1914 1915 1916 1917 1918 |
struct file_lock *lock; int can_sleep, unlock; int error; error = -EBADF; |
2903ff019
|
1919 |
if (!f.file) |
1da177e4c
|
1920 1921 1922 1923 1924 |
goto out; can_sleep = !(cmd & LOCK_NB); cmd &= ~LOCK_NB; unlock = (cmd == LOCK_UN); |
aeb5d7270
|
1925 |
if (!unlock && !(cmd & LOCK_MAND) && |
2903ff019
|
1926 |
!(f.file->f_mode & (FMODE_READ|FMODE_WRITE))) |
1da177e4c
|
1927 |
goto out_putf; |
6e129d006
|
1928 1929 1930 |
lock = flock_make_lock(f.file, cmd); if (IS_ERR(lock)) { error = PTR_ERR(lock); |
1da177e4c
|
1931 |
goto out_putf; |
6e129d006
|
1932 |
} |
1da177e4c
|
1933 1934 |
if (can_sleep) lock->fl_flags |= FL_SLEEP; |
2903ff019
|
1935 |
error = security_file_lock(f.file, lock->fl_type); |
1da177e4c
|
1936 1937 |
if (error) goto out_free; |
c568d6834
|
1938 |
if (f.file->f_op->flock && is_remote_lock(f.file)) |
2903ff019
|
1939 |
error = f.file->f_op->flock(f.file, |
1da177e4c
|
1940 1941 1942 |
(can_sleep) ? F_SETLKW : F_SETLK, lock); else |
4f6563677
|
1943 |
error = locks_lock_file_wait(f.file, lock); |
1da177e4c
|
1944 1945 |
out_free: |
993dfa877
|
1946 |
locks_free_lock(lock); |
1da177e4c
|
1947 1948 |
out_putf: |
2903ff019
|
1949 |
fdput(f); |
1da177e4c
|
1950 1951 1952 |
out: return error; } |
3ee17abd1
|
1953 1954 1955 |
/** * vfs_test_lock - test file byte range lock * @filp: The file to test lock for |
6924c5549
|
1956 |
* @fl: The lock to test; also used to hold result |
3ee17abd1
|
1957 1958 1959 1960 1961 1962 |
* * Returns -ERRNO on failure. Indicates presence of conflicting lock by * setting conf->fl_type to something other than F_UNLCK. */ int vfs_test_lock(struct file *filp, struct file_lock *fl) { |
c568d6834
|
1963 |
if (filp->f_op->lock && is_remote_lock(filp)) |
3ee17abd1
|
1964 1965 1966 1967 1968 |
return filp->f_op->lock(filp, F_GETLK, fl); posix_test_lock(filp, fl); return 0; } EXPORT_SYMBOL_GPL(vfs_test_lock); |
9d5b86ac1
|
1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 |
/** * locks_translate_pid - translate a file_lock's fl_pid number into a namespace * @fl: The file_lock who's fl_pid should be translated * @ns: The namespace into which the pid should be translated * * Used to tranlate a fl_pid into a namespace virtual pid number */ static pid_t locks_translate_pid(struct file_lock *fl, struct pid_namespace *ns) { pid_t vnr; struct pid *pid; if (IS_OFDLCK(fl)) return -1; if (IS_REMOTELCK(fl)) return fl->fl_pid; rcu_read_lock(); pid = find_pid_ns(fl->fl_pid, &init_pid_ns); vnr = pid_nr_ns(pid, ns); rcu_read_unlock(); return vnr; } |
c2fa1b8a6
|
1992 1993 |
static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) { |
9d5b86ac1
|
1994 |
flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current)); |
c2fa1b8a6
|
1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 |
#if BITS_PER_LONG == 32 /* * Make sure we can represent the posix lock via * legacy 32bit flock. */ if (fl->fl_start > OFFT_OFFSET_MAX) return -EOVERFLOW; if (fl->fl_end != OFFSET_MAX && fl->fl_end > OFFT_OFFSET_MAX) return -EOVERFLOW; #endif flock->l_start = fl->fl_start; flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : fl->fl_end - fl->fl_start + 1; flock->l_whence = 0; |
129a84de2
|
2009 |
flock->l_type = fl->fl_type; |
c2fa1b8a6
|
2010 2011 2012 2013 2014 2015 |
return 0; } #if BITS_PER_LONG == 32 static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) { |
9d5b86ac1
|
2016 |
flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current)); |
c2fa1b8a6
|
2017 2018 2019 2020 2021 2022 2023 |
flock->l_start = fl->fl_start; flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : fl->fl_end - fl->fl_start + 1; flock->l_whence = 0; flock->l_type = fl->fl_type; } #endif |
1da177e4c
|
2024 2025 2026 |
/* Report the first existing lock that would conflict with l. * This implements the F_GETLK command of fcntl(). */ |
a75d30c77
|
2027 |
int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock) |
1da177e4c
|
2028 |
{ |
52306e882
|
2029 |
struct file_lock *fl; |
1da177e4c
|
2030 |
int error; |
52306e882
|
2031 2032 2033 |
fl = locks_alloc_lock(); if (fl == NULL) return -ENOMEM; |
1da177e4c
|
2034 |
error = -EINVAL; |
a75d30c77
|
2035 |
if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK) |
1da177e4c
|
2036 |
goto out; |
52306e882
|
2037 |
error = flock_to_posix_lock(filp, fl, flock); |
1da177e4c
|
2038 2039 |
if (error) goto out; |
0d3f7a2dd
|
2040 |
if (cmd == F_OFD_GETLK) { |
90478939d
|
2041 |
error = -EINVAL; |
a75d30c77
|
2042 |
if (flock->l_pid != 0) |
90478939d
|
2043 |
goto out; |
5d50ffd7c
|
2044 |
cmd = F_GETLK; |
52306e882
|
2045 2046 |
fl->fl_flags |= FL_OFDLCK; fl->fl_owner = filp; |
5d50ffd7c
|
2047 |
} |
52306e882
|
2048 |
error = vfs_test_lock(filp, fl); |
3ee17abd1
|
2049 2050 |
if (error) goto out; |
1da177e4c
|
2051 |
|
52306e882
|
2052 2053 2054 |
flock->l_type = fl->fl_type; if (fl->fl_type != F_UNLCK) { error = posix_lock_to_flock(flock, fl); |
c2fa1b8a6
|
2055 |
if (error) |
52306e882
|
2056 |
goto out; |
1da177e4c
|
2057 |
} |
1da177e4c
|
2058 |
out: |
52306e882
|
2059 |
locks_free_lock(fl); |
1da177e4c
|
2060 2061 |
return error; } |
7723ec977
|
2062 2063 2064 2065 2066 |
/** * vfs_lock_file - file byte range lock * @filp: The file to apply the lock to * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.) * @fl: The lock to be applied |
150b39345
|
2067 2068 2069 2070 2071 2072 2073 2074 |
* @conf: Place to return a copy of the conflicting lock, if found. * * A caller that doesn't care about the conflicting lock may pass NULL * as the final argument. * * If the filesystem defines a private ->lock() method, then @conf will * be left unchanged; so a caller that cares should initialize it to * some acceptable default. |
2beb6614f
|
2075 2076 2077 2078 |
* * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX * locks, the ->lock() interface may return asynchronously, before the lock has * been granted or denied by the underlying filesystem, if (and only if) |
8fb47a4fb
|
2079 |
* lm_grant is set. Callers expecting ->lock() to return asynchronously |
2beb6614f
|
2080 2081 |
* will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if) * the request is for a blocking lock. When ->lock() does return asynchronously, |
8fb47a4fb
|
2082 |
* it must return FILE_LOCK_DEFERRED, and call ->lm_grant() when the lock |
2beb6614f
|
2083 2084 |
* request completes. * If the request is for non-blocking lock the file system should return |
bde74e4bc
|
2085 2086 |
* FILE_LOCK_DEFERRED then try to get the lock and call the callback routine * with the result. If the request timed out the callback routine will return a |
2beb6614f
|
2087 2088 2089 2090 2091 |
* nonzero return code and the file system should release the lock. The file * system is also responsible to keep a corresponding posix lock when it * grants a lock so the VFS can find out which locks are locally held and do * the correct lock cleanup when required. * The underlying filesystem must not drop the kernel lock or call |
8fb47a4fb
|
2092 |
* ->lm_grant() before returning to the caller with a FILE_LOCK_DEFERRED |
2beb6614f
|
2093 |
* return code. |
7723ec977
|
2094 |
*/ |
150b39345
|
2095 |
int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) |
7723ec977
|
2096 |
{ |
c568d6834
|
2097 |
if (filp->f_op->lock && is_remote_lock(filp)) |
7723ec977
|
2098 2099 |
return filp->f_op->lock(filp, cmd, fl); else |
150b39345
|
2100 |
return posix_lock_file(filp, fl, conf); |
7723ec977
|
2101 2102 |
} EXPORT_SYMBOL_GPL(vfs_lock_file); |
b648a6de0
|
2103 2104 2105 2106 2107 2108 2109 2110 |
static int do_lock_file_wait(struct file *filp, unsigned int cmd, struct file_lock *fl) { int error; error = security_file_lock(filp, fl->fl_type); if (error) return error; |
764c76b37
|
2111 2112 2113 |
for (;;) { error = vfs_lock_file(filp, cmd, fl, NULL); if (error != FILE_LOCK_DEFERRED) |
b648a6de0
|
2114 |
break; |
764c76b37
|
2115 2116 2117 2118 2119 2120 |
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); if (!error) continue; locks_delete_block(fl); break; |
b648a6de0
|
2121 2122 2123 2124 |
} return error; } |
6ca7d9101
|
2125 |
/* Ensure that fl->fl_file has compatible f_mode for F_SETLK calls */ |
cf01f4eef
|
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 |
static int check_fmode_for_setlk(struct file_lock *fl) { switch (fl->fl_type) { case F_RDLCK: if (!(fl->fl_file->f_mode & FMODE_READ)) return -EBADF; break; case F_WRLCK: if (!(fl->fl_file->f_mode & FMODE_WRITE)) return -EBADF; } return 0; } |
1da177e4c
|
2140 2141 2142 |
/* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). */ |
c293621bb
|
2143 |
int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, |
a75d30c77
|
2144 |
struct flock *flock) |
1da177e4c
|
2145 2146 |
{ struct file_lock *file_lock = locks_alloc_lock(); |
a75d30c77
|
2147 |
struct inode *inode = locks_inode(filp); |
0b2bac2f1
|
2148 |
struct file *f; |
1da177e4c
|
2149 2150 2151 2152 |
int error; if (file_lock == NULL) return -ENOLCK; |
1da177e4c
|
2153 2154 2155 |
/* Don't allow mandatory locks on files that may be memory mapped * and shared. */ |
a16877ca9
|
2156 |
if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) { |
1da177e4c
|
2157 2158 2159 |
error = -EAGAIN; goto out; } |
a75d30c77
|
2160 |
error = flock_to_posix_lock(filp, file_lock, flock); |
1da177e4c
|
2161 2162 |
if (error) goto out; |
5d50ffd7c
|
2163 |
|
cf01f4eef
|
2164 2165 2166 |
error = check_fmode_for_setlk(file_lock); if (error) goto out; |
5d50ffd7c
|
2167 2168 |
/* * If the cmd is requesting file-private locks, then set the |
cff2fce58
|
2169 |
* FL_OFDLCK flag and override the owner. |
5d50ffd7c
|
2170 2171 |
*/ switch (cmd) { |
0d3f7a2dd
|
2172 |
case F_OFD_SETLK: |
90478939d
|
2173 |
error = -EINVAL; |
a75d30c77
|
2174 |
if (flock->l_pid != 0) |
90478939d
|
2175 |
goto out; |
5d50ffd7c
|
2176 |
cmd = F_SETLK; |
cff2fce58
|
2177 |
file_lock->fl_flags |= FL_OFDLCK; |
73a8f5f7e
|
2178 |
file_lock->fl_owner = filp; |
5d50ffd7c
|
2179 |
break; |
0d3f7a2dd
|
2180 |
case F_OFD_SETLKW: |
90478939d
|
2181 |
error = -EINVAL; |
a75d30c77
|
2182 |
if (flock->l_pid != 0) |
90478939d
|
2183 |
goto out; |
5d50ffd7c
|
2184 |
cmd = F_SETLKW; |
cff2fce58
|
2185 |
file_lock->fl_flags |= FL_OFDLCK; |
73a8f5f7e
|
2186 |
file_lock->fl_owner = filp; |
5d50ffd7c
|
2187 2188 |
/* Fallthrough */ case F_SETLKW: |
1da177e4c
|
2189 2190 |
file_lock->fl_flags |= FL_SLEEP; } |
5d50ffd7c
|
2191 |
|
b648a6de0
|
2192 |
error = do_lock_file_wait(filp, cmd, file_lock); |
1da177e4c
|
2193 |
|
c293621bb
|
2194 |
/* |
0752ba807
|
2195 2196 2197 |
* Attempt to detect a close/fcntl race and recover by releasing the * lock that was just acquired. There is no need to do that when we're * unlocking though, or for OFD locks. |
c293621bb
|
2198 |
*/ |
0752ba807
|
2199 2200 |
if (!error && file_lock->fl_type != F_UNLCK && !(file_lock->fl_flags & FL_OFDLCK)) { |
7f3697e24
|
2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 |
/* * We need that spin_lock here - it prevents reordering between * update of i_flctx->flc_posix and check for it done in * close(). rcu_read_lock() wouldn't do. */ spin_lock(¤t->files->file_lock); f = fcheck(fd); spin_unlock(¤t->files->file_lock); if (f != filp) { file_lock->fl_type = F_UNLCK; error = do_lock_file_wait(filp, cmd, file_lock); WARN_ON_ONCE(error); error = -EBADF; } |
1da177e4c
|
2215 |
} |
c293621bb
|
2216 |
out: |
1890910fd
|
2217 |
trace_fcntl_setlk(inode, file_lock, error); |
1da177e4c
|
2218 2219 2220 2221 2222 2223 2224 2225 |
locks_free_lock(file_lock); return error; } #if BITS_PER_LONG == 32 /* Report the first existing lock that would conflict with l. * This implements the F_GETLK command of fcntl(). */ |
a75d30c77
|
2226 |
int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock) |
1da177e4c
|
2227 |
{ |
52306e882
|
2228 |
struct file_lock *fl; |
1da177e4c
|
2229 |
int error; |
52306e882
|
2230 2231 2232 |
fl = locks_alloc_lock(); if (fl == NULL) return -ENOMEM; |
1da177e4c
|
2233 |
error = -EINVAL; |
a75d30c77
|
2234 |
if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK) |
1da177e4c
|
2235 |
goto out; |
52306e882
|
2236 |
error = flock64_to_posix_lock(filp, fl, flock); |
1da177e4c
|
2237 2238 |
if (error) goto out; |
0d3f7a2dd
|
2239 |
if (cmd == F_OFD_GETLK) { |
90478939d
|
2240 |
error = -EINVAL; |
a75d30c77
|
2241 |
if (flock->l_pid != 0) |
90478939d
|
2242 |
goto out; |
5d50ffd7c
|
2243 |
cmd = F_GETLK64; |
52306e882
|
2244 2245 |
fl->fl_flags |= FL_OFDLCK; fl->fl_owner = filp; |
5d50ffd7c
|
2246 |
} |
52306e882
|
2247 |
error = vfs_test_lock(filp, fl); |
3ee17abd1
|
2248 2249 |
if (error) goto out; |
52306e882
|
2250 2251 2252 |
flock->l_type = fl->fl_type; if (fl->fl_type != F_UNLCK) posix_lock_to_flock64(flock, fl); |
f328296e2
|
2253 |
|
1da177e4c
|
2254 |
out: |
52306e882
|
2255 |
locks_free_lock(fl); |
1da177e4c
|
2256 2257 2258 2259 2260 2261 |
return error; } /* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). */ |
c293621bb
|
2262 |
int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, |
a75d30c77
|
2263 |
struct flock64 *flock) |
1da177e4c
|
2264 2265 |
{ struct file_lock *file_lock = locks_alloc_lock(); |
a75d30c77
|
2266 |
struct inode *inode = locks_inode(filp); |
0b2bac2f1
|
2267 |
struct file *f; |
1da177e4c
|
2268 2269 2270 2271 |
int error; if (file_lock == NULL) return -ENOLCK; |
1da177e4c
|
2272 2273 2274 |
/* Don't allow mandatory locks on files that may be memory mapped * and shared. */ |
a16877ca9
|
2275 |
if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) { |
1da177e4c
|
2276 2277 2278 |
error = -EAGAIN; goto out; } |
a75d30c77
|
2279 |
error = flock64_to_posix_lock(filp, file_lock, flock); |
1da177e4c
|
2280 2281 |
if (error) goto out; |
5d50ffd7c
|
2282 |
|
cf01f4eef
|
2283 2284 2285 |
error = check_fmode_for_setlk(file_lock); if (error) goto out; |
5d50ffd7c
|
2286 2287 |
/* * If the cmd is requesting file-private locks, then set the |
cff2fce58
|
2288 |
* FL_OFDLCK flag and override the owner. |
5d50ffd7c
|
2289 2290 |
*/ switch (cmd) { |
0d3f7a2dd
|
2291 |
case F_OFD_SETLK: |
90478939d
|
2292 |
error = -EINVAL; |
a75d30c77
|
2293 |
if (flock->l_pid != 0) |
90478939d
|
2294 |
goto out; |
5d50ffd7c
|
2295 |
cmd = F_SETLK64; |
cff2fce58
|
2296 |
file_lock->fl_flags |= FL_OFDLCK; |
73a8f5f7e
|
2297 |
file_lock->fl_owner = filp; |
5d50ffd7c
|
2298 |
break; |
0d3f7a2dd
|
2299 |
case F_OFD_SETLKW: |
90478939d
|
2300 |
error = -EINVAL; |
a75d30c77
|
2301 |
if (flock->l_pid != 0) |
90478939d
|
2302 |
goto out; |
5d50ffd7c
|
2303 |
cmd = F_SETLKW64; |
cff2fce58
|
2304 |
file_lock->fl_flags |= FL_OFDLCK; |
73a8f5f7e
|
2305 |
file_lock->fl_owner = filp; |
5d50ffd7c
|
2306 2307 |
/* Fallthrough */ case F_SETLKW64: |
1da177e4c
|
2308 2309 |
file_lock->fl_flags |= FL_SLEEP; } |
5d50ffd7c
|
2310 |
|
b648a6de0
|
2311 |
error = do_lock_file_wait(filp, cmd, file_lock); |
1da177e4c
|
2312 |
|
c293621bb
|
2313 |
/* |
0752ba807
|
2314 2315 2316 |
* Attempt to detect a close/fcntl race and recover by releasing the * lock that was just acquired. There is no need to do that when we're * unlocking though, or for OFD locks. |
c293621bb
|
2317 |
*/ |
0752ba807
|
2318 2319 |
if (!error && file_lock->fl_type != F_UNLCK && !(file_lock->fl_flags & FL_OFDLCK)) { |
7f3697e24
|
2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 |
/* * We need that spin_lock here - it prevents reordering between * update of i_flctx->flc_posix and check for it done in * close(). rcu_read_lock() wouldn't do. */ spin_lock(¤t->files->file_lock); f = fcheck(fd); spin_unlock(¤t->files->file_lock); if (f != filp) { file_lock->fl_type = F_UNLCK; error = do_lock_file_wait(filp, cmd, file_lock); WARN_ON_ONCE(error); error = -EBADF; } |
1da177e4c
|
2334 |
} |
1da177e4c
|
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 |
out: locks_free_lock(file_lock); return error; } #endif /* BITS_PER_LONG == 32 */ /* * This function is called when the file is being removed * from the task's fd array. POSIX locks belonging to this task * are deleted at this time. */ void locks_remove_posix(struct file *filp, fl_owner_t owner) { |
1890910fd
|
2348 |
int error; |
c568d6834
|
2349 |
struct inode *inode = locks_inode(filp); |
ff7b86b82
|
2350 |
struct file_lock lock; |
128a37852
|
2351 |
struct file_lock_context *ctx; |
1da177e4c
|
2352 2353 2354 2355 2356 2357 |
/* * If there are no locks held on this file, we don't need to call * posix_lock_file(). Another process could be setting a lock on this * file at the same time, but we wouldn't remove that lock anyway. */ |
c568d6834
|
2358 |
ctx = smp_load_acquire(&inode->i_flctx); |
bd61e0a9c
|
2359 |
if (!ctx || list_empty(&ctx->flc_posix)) |
1da177e4c
|
2360 2361 2362 |
return; lock.fl_type = F_UNLCK; |
75e1fcc0b
|
2363 |
lock.fl_flags = FL_POSIX | FL_CLOSE; |
1da177e4c
|
2364 2365 2366 2367 2368 2369 2370 |
lock.fl_start = 0; lock.fl_end = OFFSET_MAX; lock.fl_owner = owner; lock.fl_pid = current->tgid; lock.fl_file = filp; lock.fl_ops = NULL; lock.fl_lmops = NULL; |
1890910fd
|
2371 |
error = vfs_lock_file(filp, F_SETLK, &lock, NULL); |
1da177e4c
|
2372 |
|
1da177e4c
|
2373 2374 |
if (lock.fl_ops && lock.fl_ops->fl_release_private) lock.fl_ops->fl_release_private(&lock); |
c568d6834
|
2375 |
trace_locks_remove_posix(inode, &lock, error); |
1da177e4c
|
2376 2377 2378 |
} EXPORT_SYMBOL(locks_remove_posix); |
3d8e560de
|
2379 |
/* The i_flctx must be valid when calling into here */ |
dd459bb19
|
2380 |
static void |
128a37852
|
2381 |
locks_remove_flock(struct file *filp, struct file_lock_context *flctx) |
dd459bb19
|
2382 2383 2384 2385 2386 |
{ struct file_lock fl = { .fl_owner = filp, .fl_pid = current->tgid, .fl_file = filp, |
50f2112cf
|
2387 |
.fl_flags = FL_FLOCK | FL_CLOSE, |
dd459bb19
|
2388 2389 2390 |
.fl_type = F_UNLCK, .fl_end = OFFSET_MAX, }; |
c568d6834
|
2391 |
struct inode *inode = locks_inode(filp); |
dd459bb19
|
2392 |
|
3d8e560de
|
2393 |
if (list_empty(&flctx->flc_flock)) |
dd459bb19
|
2394 |
return; |
c568d6834
|
2395 |
if (filp->f_op->flock && is_remote_lock(filp)) |
dd459bb19
|
2396 2397 |
filp->f_op->flock(filp, F_SETLKW, &fl); else |
bcd7f78d0
|
2398 |
flock_lock_inode(inode, &fl); |
dd459bb19
|
2399 2400 2401 2402 |
if (fl.fl_ops && fl.fl_ops->fl_release_private) fl.fl_ops->fl_release_private(&fl); } |
3d8e560de
|
2403 |
/* The i_flctx must be valid when calling into here */ |
8634b51f6
|
2404 |
static void |
128a37852
|
2405 |
locks_remove_lease(struct file *filp, struct file_lock_context *ctx) |
8634b51f6
|
2406 |
{ |
8634b51f6
|
2407 2408 |
struct file_lock *fl, *tmp; LIST_HEAD(dispose); |
3d8e560de
|
2409 |
if (list_empty(&ctx->flc_lease)) |
8634b51f6
|
2410 |
return; |
5f43086bb
|
2411 |
percpu_down_read_preempt_disable(&file_rwsem); |
6109c8503
|
2412 |
spin_lock(&ctx->flc_lock); |
8634b51f6
|
2413 |
list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) |
c4e136cda
|
2414 2415 |
if (filp == fl->fl_file) lease_modify(fl, F_UNLCK, &dispose); |
6109c8503
|
2416 |
spin_unlock(&ctx->flc_lock); |
5f43086bb
|
2417 |
percpu_up_read_preempt_enable(&file_rwsem); |
8634b51f6
|
2418 2419 |
locks_dispose_list(&dispose); } |
1da177e4c
|
2420 2421 2422 |
/* * This function is called on the last close of an open file. */ |
78ed8a133
|
2423 |
void locks_remove_file(struct file *filp) |
1da177e4c
|
2424 |
{ |
128a37852
|
2425 |
struct file_lock_context *ctx; |
c568d6834
|
2426 |
ctx = smp_load_acquire(&locks_inode(filp)->i_flctx); |
128a37852
|
2427 |
if (!ctx) |
3d8e560de
|
2428 |
return; |
dd459bb19
|
2429 |
/* remove any OFD locks */ |
73a8f5f7e
|
2430 |
locks_remove_posix(filp, filp); |
5d50ffd7c
|
2431 |
|
dd459bb19
|
2432 |
/* remove flock locks */ |
128a37852
|
2433 |
locks_remove_flock(filp, ctx); |
dd459bb19
|
2434 |
|
8634b51f6
|
2435 |
/* remove any leases */ |
128a37852
|
2436 |
locks_remove_lease(filp, ctx); |
3953704fd
|
2437 2438 2439 2440 2441 2442 |
spin_lock(&ctx->flc_lock); locks_check_ctx_file_list(filp, &ctx->flc_posix, "POSIX"); locks_check_ctx_file_list(filp, &ctx->flc_flock, "FLOCK"); locks_check_ctx_file_list(filp, &ctx->flc_lease, "LEASE"); spin_unlock(&ctx->flc_lock); |
1da177e4c
|
2443 2444 2445 |
} /** |
1da177e4c
|
2446 |
* posix_unblock_lock - stop waiting for a file lock |
1da177e4c
|
2447 2448 2449 2450 |
* @waiter: the lock which was waiting * * lockd needs to block waiting for locks. */ |
64a318ee2
|
2451 |
int |
f891a29f4
|
2452 |
posix_unblock_lock(struct file_lock *waiter) |
1da177e4c
|
2453 |
{ |
64a318ee2
|
2454 |
int status = 0; |
7b2296afb
|
2455 |
spin_lock(&blocked_lock_lock); |
5996a298d
|
2456 |
if (waiter->fl_next) |
1da177e4c
|
2457 |
__locks_delete_block(waiter); |
64a318ee2
|
2458 2459 |
else status = -ENOENT; |
7b2296afb
|
2460 |
spin_unlock(&blocked_lock_lock); |
64a318ee2
|
2461 |
return status; |
1da177e4c
|
2462 |
} |
1da177e4c
|
2463 |
EXPORT_SYMBOL(posix_unblock_lock); |
9b9d2ab41
|
2464 2465 2466 2467 2468 2469 2470 2471 2472 |
/** * vfs_cancel_lock - file byte range unblock lock * @filp: The file to apply the unblock to * @fl: The lock to be unblocked * * Used by lock managers to cancel blocked requests */ int vfs_cancel_lock(struct file *filp, struct file_lock *fl) { |
c568d6834
|
2473 |
if (filp->f_op->lock && is_remote_lock(filp)) |
9b9d2ab41
|
2474 2475 2476 2477 2478 |
return filp->f_op->lock(filp, F_CANCELLK, fl); return 0; } EXPORT_SYMBOL_GPL(vfs_cancel_lock); |
7f8ada98d
|
2479 |
#ifdef CONFIG_PROC_FS |
d8ba7a363
|
2480 |
#include <linux/proc_fs.h> |
7f8ada98d
|
2481 |
#include <linux/seq_file.h> |
7012b02a2
|
2482 2483 2484 2485 |
struct locks_iterator { int li_cpu; loff_t li_pos; }; |
7f8ada98d
|
2486 |
static void lock_get_status(struct seq_file *f, struct file_lock *fl, |
99dc82925
|
2487 |
loff_t id, char *pfx) |
1da177e4c
|
2488 2489 |
{ struct inode *inode = NULL; |
ab1f16116
|
2490 |
unsigned int fl_pid; |
9d5b86ac1
|
2491 |
struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info; |
ab1f16116
|
2492 |
|
9d5b86ac1
|
2493 2494 2495 2496 2497 2498 2499 2500 |
fl_pid = locks_translate_pid(fl, proc_pidns); /* * If there isn't a fl_pid don't display who is waiting on * the lock if we are called from locks_show, or if we are * called from __show_fd_info - skip lock entirely */ if (fl_pid == 0) return; |
1da177e4c
|
2501 2502 |
if (fl->fl_file != NULL) |
c568d6834
|
2503 |
inode = locks_inode(fl->fl_file); |
1da177e4c
|
2504 |
|
99dc82925
|
2505 |
seq_printf(f, "%lld:%s ", id, pfx); |
1da177e4c
|
2506 |
if (IS_POSIX(fl)) { |
c918d42a2
|
2507 |
if (fl->fl_flags & FL_ACCESS) |
5315c26a6
|
2508 |
seq_puts(f, "ACCESS"); |
cff2fce58
|
2509 |
else if (IS_OFDLCK(fl)) |
5315c26a6
|
2510 |
seq_puts(f, "OFDLCK"); |
c918d42a2
|
2511 |
else |
5315c26a6
|
2512 |
seq_puts(f, "POSIX "); |
c918d42a2
|
2513 2514 |
seq_printf(f, " %s ", |
1da177e4c
|
2515 |
(inode == NULL) ? "*NOINODE*" : |
a16877ca9
|
2516 |
mandatory_lock(inode) ? "MANDATORY" : "ADVISORY "); |
1da177e4c
|
2517 2518 |
} else if (IS_FLOCK(fl)) { if (fl->fl_type & LOCK_MAND) { |
5315c26a6
|
2519 |
seq_puts(f, "FLOCK MSNFS "); |
1da177e4c
|
2520 |
} else { |
5315c26a6
|
2521 |
seq_puts(f, "FLOCK ADVISORY "); |
1da177e4c
|
2522 2523 |
} } else if (IS_LEASE(fl)) { |
8144f1f69
|
2524 2525 2526 2527 |
if (fl->fl_flags & FL_DELEG) seq_puts(f, "DELEG "); else seq_puts(f, "LEASE "); |
ab83fa4b4
|
2528 |
if (lease_breaking(fl)) |
5315c26a6
|
2529 |
seq_puts(f, "BREAKING "); |
1da177e4c
|
2530 |
else if (fl->fl_file) |
5315c26a6
|
2531 |
seq_puts(f, "ACTIVE "); |
1da177e4c
|
2532 |
else |
5315c26a6
|
2533 |
seq_puts(f, "BREAKER "); |
1da177e4c
|
2534 |
} else { |
5315c26a6
|
2535 |
seq_puts(f, "UNKNOWN UNKNOWN "); |
1da177e4c
|
2536 2537 |
} if (fl->fl_type & LOCK_MAND) { |
7f8ada98d
|
2538 |
seq_printf(f, "%s ", |
1da177e4c
|
2539 2540 2541 2542 |
(fl->fl_type & LOCK_READ) ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); } else { |
7f8ada98d
|
2543 |
seq_printf(f, "%s ", |
ab83fa4b4
|
2544 |
(lease_breaking(fl)) |
0ee5c6d63
|
2545 2546 |
? (fl->fl_type == F_UNLCK) ? "UNLCK" : "READ " : (fl->fl_type == F_WRLCK) ? "WRITE" : "READ "); |
1da177e4c
|
2547 2548 |
} if (inode) { |
3648888e9
|
2549 |
/* userspace relies on this representation of dev_t */ |
ab1f16116
|
2550 |
seq_printf(f, "%d %02x:%02x:%ld ", fl_pid, |
1da177e4c
|
2551 2552 |
MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), inode->i_ino); |
1da177e4c
|
2553 |
} else { |
ab1f16116
|
2554 |
seq_printf(f, "%d <none>:0 ", fl_pid); |
1da177e4c
|
2555 2556 2557 |
} if (IS_POSIX(fl)) { if (fl->fl_end == OFFSET_MAX) |
7f8ada98d
|
2558 2559 |
seq_printf(f, "%Ld EOF ", fl->fl_start); |
1da177e4c
|
2560 |
else |
7f8ada98d
|
2561 2562 |
seq_printf(f, "%Ld %Ld ", fl->fl_start, fl->fl_end); |
1da177e4c
|
2563 |
} else { |
5315c26a6
|
2564 2565 |
seq_puts(f, "0 EOF "); |
1da177e4c
|
2566 2567 |
} } |
7f8ada98d
|
2568 |
static int locks_show(struct seq_file *f, void *v) |
1da177e4c
|
2569 |
{ |
7012b02a2
|
2570 |
struct locks_iterator *iter = f->private; |
7f8ada98d
|
2571 |
struct file_lock *fl, *bfl; |
d67fd44f6
|
2572 |
struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info; |
1da177e4c
|
2573 |
|
139ca04ee
|
2574 |
fl = hlist_entry(v, struct file_lock, fl_link); |
1da177e4c
|
2575 |
|
9d5b86ac1
|
2576 |
if (locks_translate_pid(fl, proc_pidns) == 0) |
d67fd44f6
|
2577 |
return 0; |
7012b02a2
|
2578 |
lock_get_status(f, fl, iter->li_pos, ""); |
1da177e4c
|
2579 |
|
7f8ada98d
|
2580 |
list_for_each_entry(bfl, &fl->fl_block, fl_block) |
7012b02a2
|
2581 |
lock_get_status(f, bfl, iter->li_pos, " ->"); |
094f28252
|
2582 |
|
7f8ada98d
|
2583 2584 |
return 0; } |
1da177e4c
|
2585 |
|
6c8c90319
|
2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 |
static void __show_fd_locks(struct seq_file *f, struct list_head *head, int *id, struct file *filp, struct files_struct *files) { struct file_lock *fl; list_for_each_entry(fl, head, fl_list) { if (filp != fl->fl_file) continue; if (fl->fl_owner != files && fl->fl_owner != filp) continue; (*id)++; seq_puts(f, "lock:\t"); lock_get_status(f, fl, *id, ""); } } void show_fd_locks(struct seq_file *f, struct file *filp, struct files_struct *files) { |
c568d6834
|
2609 |
struct inode *inode = locks_inode(filp); |
6c8c90319
|
2610 2611 |
struct file_lock_context *ctx; int id = 0; |
128a37852
|
2612 |
ctx = smp_load_acquire(&inode->i_flctx); |
6c8c90319
|
2613 2614 2615 2616 2617 2618 2619 2620 2621 |
if (!ctx) return; spin_lock(&ctx->flc_lock); __show_fd_locks(f, &ctx->flc_flock, &id, filp, files); __show_fd_locks(f, &ctx->flc_posix, &id, filp, files); __show_fd_locks(f, &ctx->flc_lease, &id, filp, files); spin_unlock(&ctx->flc_lock); } |
7f8ada98d
|
2622 |
static void *locks_start(struct seq_file *f, loff_t *pos) |
b03dfdec0
|
2623 |
__acquires(&blocked_lock_lock) |
7f8ada98d
|
2624 |
{ |
7012b02a2
|
2625 |
struct locks_iterator *iter = f->private; |
99dc82925
|
2626 |
|
7012b02a2
|
2627 |
iter->li_pos = *pos + 1; |
aba376607
|
2628 |
percpu_down_write(&file_rwsem); |
7b2296afb
|
2629 |
spin_lock(&blocked_lock_lock); |
7c3f654d8
|
2630 |
return seq_hlist_start_percpu(&file_lock_list.hlist, &iter->li_cpu, *pos); |
7f8ada98d
|
2631 |
} |
1da177e4c
|
2632 |
|
7f8ada98d
|
2633 2634 |
static void *locks_next(struct seq_file *f, void *v, loff_t *pos) { |
7012b02a2
|
2635 2636 2637 |
struct locks_iterator *iter = f->private; ++iter->li_pos; |
7c3f654d8
|
2638 |
return seq_hlist_next_percpu(v, &file_lock_list.hlist, &iter->li_cpu, pos); |
7f8ada98d
|
2639 |
} |
1da177e4c
|
2640 |
|
7f8ada98d
|
2641 |
static void locks_stop(struct seq_file *f, void *v) |
b03dfdec0
|
2642 |
__releases(&blocked_lock_lock) |
7f8ada98d
|
2643 |
{ |
7b2296afb
|
2644 |
spin_unlock(&blocked_lock_lock); |
aba376607
|
2645 |
percpu_up_write(&file_rwsem); |
1da177e4c
|
2646 |
} |
d8ba7a363
|
2647 |
static const struct seq_operations locks_seq_operations = { |
7f8ada98d
|
2648 2649 2650 2651 2652 |
.start = locks_start, .next = locks_next, .stop = locks_stop, .show = locks_show, }; |
d8ba7a363
|
2653 |
|
d8ba7a363
|
2654 2655 |
static int __init proc_locks_init(void) { |
44414d82c
|
2656 2657 |
proc_create_seq_private("locks", 0, NULL, &locks_seq_operations, sizeof(struct locks_iterator), NULL); |
d8ba7a363
|
2658 2659 |
return 0; } |
918992267
|
2660 |
fs_initcall(proc_locks_init); |
7f8ada98d
|
2661 |
#endif |
1da177e4c
|
2662 2663 |
static int __init filelock_init(void) { |
7012b02a2
|
2664 |
int i; |
4a075e39c
|
2665 2666 |
flctx_cache = kmem_cache_create("file_lock_ctx", sizeof(struct file_lock_context), 0, SLAB_PANIC, NULL); |
1da177e4c
|
2667 |
filelock_cache = kmem_cache_create("file_lock_cache", |
ee19cc406
|
2668 |
sizeof(struct file_lock), 0, SLAB_PANIC, NULL); |
7012b02a2
|
2669 |
|
7c3f654d8
|
2670 2671 2672 2673 2674 2675 |
for_each_possible_cpu(i) { struct file_lock_list_struct *fll = per_cpu_ptr(&file_lock_list, i); spin_lock_init(&fll->lock); INIT_HLIST_HEAD(&fll->hlist); } |
7012b02a2
|
2676 |
|
1da177e4c
|
2677 2678 2679 2680 |
return 0; } core_initcall(filelock_init); |