summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-04-25 09:26:52 -0400
committerDavid Howells <dhowells@redhat.com>2019-04-25 09:26:52 -0400
commit6c6c1d63c243025956f061e67fff3a615aa0f6be (patch)
tree2dc16f2dfa389efcc4b53197a33a9654cf02f794
parent80548b03991f58758a336424a90bf9f988e3b077 (diff)
afs: Provide mount-time configurable byte-range file locking emulation
Provide byte-range file locking emulation that can be configured at mount time to one of four modes: (1) flock=local. Locking is done locally only and no reference is made to the server. (2) flock=openafs. Byte-range locking is done locally only; whole-file locking is done with reference to the server. Whole-file locks cannot be upgraded unless the client holds an exclusive lock. (3) flock=strict. Byte-range and whole-file locking both require a sufficient whole-file lock on the server. (4) flock=write. As strict, but the client always gets an exclusive whole-file lock on the server. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--fs/afs/flock.c49
-rw-r--r--fs/afs/fsclient.c2
-rw-r--r--fs/afs/internal.h14
-rw-r--r--fs/afs/super.c27
-rw-r--r--fs/afs/yfsclient.c2
-rw-r--r--include/trace/events/afs.h35
6 files changed, 120 insertions, 9 deletions
diff --git a/fs/afs/flock.c b/fs/afs/flock.c
index 325bf731d8dd..ef313f4c1d11 100644
--- a/fs/afs/flock.c
+++ b/fs/afs/flock.c
@@ -409,7 +409,7 @@ static void afs_defer_unlock(struct afs_vnode *vnode)
409 * whether we think that we have a locking permit. 409 * whether we think that we have a locking permit.
410 */ 410 */
411static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key, 411static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key,
412 afs_lock_type_t type, bool can_sleep) 412 enum afs_flock_mode mode, afs_lock_type_t type)
413{ 413{
414 afs_access_t access; 414 afs_access_t access;
415 int ret; 415 int ret;
@@ -437,13 +437,9 @@ static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key,
437 if (type == AFS_LOCK_READ) { 437 if (type == AFS_LOCK_READ) {
438 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE | AFS_ACE_LOCK))) 438 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE | AFS_ACE_LOCK)))
439 return -EACCES; 439 return -EACCES;
440 if (vnode->status.lock_count == -1 && !can_sleep)
441 return -EAGAIN; /* Write locked */
442 } else { 440 } else {
443 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE))) 441 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE)))
444 return -EACCES; 442 return -EACCES;
445 if (vnode->status.lock_count != 0 && !can_sleep)
446 return -EAGAIN; /* Locked */
447 } 443 }
448 444
449 return 0; 445 return 0;
@@ -456,24 +452,48 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
456{ 452{
457 struct inode *inode = locks_inode(file); 453 struct inode *inode = locks_inode(file);
458 struct afs_vnode *vnode = AFS_FS_I(inode); 454 struct afs_vnode *vnode = AFS_FS_I(inode);
455 enum afs_flock_mode mode = AFS_FS_S(inode->i_sb)->flock_mode;
459 afs_lock_type_t type; 456 afs_lock_type_t type;
460 struct key *key = afs_file_key(file); 457 struct key *key = afs_file_key(file);
458 bool partial, no_server_lock = false;
461 int ret; 459 int ret;
462 460
463 _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type); 461 if (mode == afs_flock_mode_unset)
462 mode = afs_flock_mode_openafs;
463
464 _enter("{%llx:%llu},%llu-%llu,%u,%u",
465 vnode->fid.vid, vnode->fid.vnode,
466 fl->fl_start, fl->fl_end, fl->fl_type, mode);
464 467
465 fl->fl_ops = &afs_lock_ops; 468 fl->fl_ops = &afs_lock_ops;
466 INIT_LIST_HEAD(&fl->fl_u.afs.link); 469 INIT_LIST_HEAD(&fl->fl_u.afs.link);
467 fl->fl_u.afs.state = AFS_LOCK_PENDING; 470 fl->fl_u.afs.state = AFS_LOCK_PENDING;
468 471
472 partial = (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX);
469 type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; 473 type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
474 if (mode == afs_flock_mode_write && partial)
475 type = AFS_LOCK_WRITE;
470 476
471 ret = afs_do_setlk_check(vnode, key, type, fl->fl_flags & FL_SLEEP); 477 ret = afs_do_setlk_check(vnode, key, mode, type);
472 if (ret < 0) 478 if (ret < 0)
473 return ret; 479 return ret;
474 480
475 trace_afs_flock_op(vnode, fl, afs_flock_op_set_lock); 481 trace_afs_flock_op(vnode, fl, afs_flock_op_set_lock);
476 482
483 /* AFS3 protocol only supports full-file locks and doesn't provide any
484 * method of upgrade/downgrade, so we need to emulate for partial-file
485 * locks.
486 *
487 * The OpenAFS client only gets a server lock for a full-file lock and
488 * keeps partial-file locks local. Allow this behaviour to be emulated
489 * (as the default).
490 */
491 if (mode == afs_flock_mode_local ||
492 (partial && mode == afs_flock_mode_openafs)) {
493 no_server_lock = true;
494 goto skip_server_lock;
495 }
496
477 spin_lock(&vnode->lock); 497 spin_lock(&vnode->lock);
478 list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks); 498 list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks);
479 499
@@ -502,6 +522,18 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
502 } 522 }
503 } 523 }
504 524
525 if (vnode->lock_state == AFS_VNODE_LOCK_NONE &&
526 !(fl->fl_flags & FL_SLEEP)) {
527 ret = -EAGAIN;
528 if (type == AFS_LOCK_READ) {
529 if (vnode->status.lock_count == -1)
530 goto lock_is_contended; /* Write locked */
531 } else {
532 if (vnode->status.lock_count != 0)
533 goto lock_is_contended; /* Locked */
534 }
535 }
536
505 if (vnode->lock_state != AFS_VNODE_LOCK_NONE) 537 if (vnode->lock_state != AFS_VNODE_LOCK_NONE)
506 goto need_to_wait; 538 goto need_to_wait;
507 539
@@ -571,6 +603,7 @@ vnode_is_locked:
571 /* the lock has been granted by the server... */ 603 /* the lock has been granted by the server... */
572 ASSERTCMP(fl->fl_u.afs.state, ==, AFS_LOCK_GRANTED); 604 ASSERTCMP(fl->fl_u.afs.state, ==, AFS_LOCK_GRANTED);
573 605
606skip_server_lock:
574 /* ... but the VFS still needs to distribute access on this client. */ 607 /* ... but the VFS still needs to distribute access on this client. */
575 trace_afs_flock_ev(vnode, fl, afs_flock_vfs_locking, 0); 608 trace_afs_flock_ev(vnode, fl, afs_flock_vfs_locking, 0);
576 ret = locks_lock_file_wait(file, fl); 609 ret = locks_lock_file_wait(file, fl);
@@ -649,6 +682,8 @@ vfs_rejected_lock:
649 * deal with. 682 * deal with.
650 */ 683 */
651 _debug("vfs refused %d", ret); 684 _debug("vfs refused %d", ret);
685 if (no_server_lock)
686 goto error;
652 spin_lock(&vnode->lock); 687 spin_lock(&vnode->lock);
653 list_del_init(&fl->fl_u.afs.link); 688 list_del_init(&fl->fl_u.afs.link);
654 afs_defer_unlock(vnode); 689 afs_defer_unlock(vnode);
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index be4520eb4965..9b73a57aa5cb 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -1902,7 +1902,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
1902 *bp++ = htonl(type); 1902 *bp++ = htonl(type);
1903 1903
1904 afs_use_fs_server(call, fc->cbi); 1904 afs_use_fs_server(call, fc->cbi);
1905 trace_afs_make_fs_call(call, &vnode->fid); 1905 trace_afs_make_fs_calli(call, &vnode->fid, type);
1906 afs_make_call(&fc->ac, call, GFP_NOFS); 1906 afs_make_call(&fc->ac, call, GFP_NOFS);
1907 return afs_wait_for_call_to_complete(call, &fc->ac); 1907 return afs_wait_for_call_to_complete(call, &fc->ac);
1908} 1908}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 20fd44de26ac..91204e1428f2 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -36,11 +36,24 @@
36struct pagevec; 36struct pagevec;
37struct afs_call; 37struct afs_call;
38 38
39/*
40 * Partial file-locking emulation mode. (The problem being that AFS3 only
41 * allows whole-file locks and no upgrading/downgrading).
42 */
43enum afs_flock_mode {
44 afs_flock_mode_unset,
45 afs_flock_mode_local, /* Local locking only */
46 afs_flock_mode_openafs, /* Don't get server lock for a partial lock */
47 afs_flock_mode_strict, /* Always get a server lock for a partial lock */
48 afs_flock_mode_write, /* Get an exclusive server lock for a partial lock */
49};
50
39struct afs_fs_context { 51struct afs_fs_context {
40 bool force; /* T to force cell type */ 52 bool force; /* T to force cell type */
41 bool autocell; /* T if set auto mount operation */ 53 bool autocell; /* T if set auto mount operation */
42 bool dyn_root; /* T if dynamic root */ 54 bool dyn_root; /* T if dynamic root */
43 bool no_cell; /* T if the source is "none" (for dynroot) */ 55 bool no_cell; /* T if the source is "none" (for dynroot) */
56 enum afs_flock_mode flock_mode; /* Partial file-locking emulation mode */
44 afs_voltype_t type; /* type of volume requested */ 57 afs_voltype_t type; /* type of volume requested */
45 unsigned int volnamesz; /* size of volume name */ 58 unsigned int volnamesz; /* size of volume name */
46 const char *volname; /* name of volume to mount */ 59 const char *volname; /* name of volume to mount */
@@ -221,6 +234,7 @@ struct afs_super_info {
221 struct net *net_ns; /* Network namespace */ 234 struct net *net_ns; /* Network namespace */
222 struct afs_cell *cell; /* The cell in which the volume resides */ 235 struct afs_cell *cell; /* The cell in which the volume resides */
223 struct afs_volume *volume; /* volume record */ 236 struct afs_volume *volume; /* volume record */
237 enum afs_flock_mode flock_mode:8; /* File locking emulation mode */
224 bool dyn_root; /* True if dynamic root */ 238 bool dyn_root; /* True if dynamic root */
225}; 239};
226 240
diff --git a/fs/afs/super.c b/fs/afs/super.c
index ce85ae61f12d..18334fa1a0d2 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -67,19 +67,30 @@ static atomic_t afs_count_active_inodes;
67enum afs_param { 67enum afs_param {
68 Opt_autocell, 68 Opt_autocell,
69 Opt_dyn, 69 Opt_dyn,
70 Opt_flock,
70 Opt_source, 71 Opt_source,
71}; 72};
72 73
73static const struct fs_parameter_spec afs_param_specs[] = { 74static const struct fs_parameter_spec afs_param_specs[] = {
74 fsparam_flag ("autocell", Opt_autocell), 75 fsparam_flag ("autocell", Opt_autocell),
75 fsparam_flag ("dyn", Opt_dyn), 76 fsparam_flag ("dyn", Opt_dyn),
77 fsparam_enum ("flock", Opt_flock),
76 fsparam_string("source", Opt_source), 78 fsparam_string("source", Opt_source),
77 {} 79 {}
78}; 80};
79 81
82static const struct fs_parameter_enum afs_param_enums[] = {
83 { Opt_flock, "local", afs_flock_mode_local },
84 { Opt_flock, "openafs", afs_flock_mode_openafs },
85 { Opt_flock, "strict", afs_flock_mode_strict },
86 { Opt_flock, "write", afs_flock_mode_write },
87 {}
88};
89
80static const struct fs_parameter_description afs_fs_parameters = { 90static const struct fs_parameter_description afs_fs_parameters = {
81 .name = "kAFS", 91 .name = "kAFS",
82 .specs = afs_param_specs, 92 .specs = afs_param_specs,
93 .enums = afs_param_enums,
83}; 94};
84 95
85/* 96/*
@@ -182,11 +193,22 @@ static int afs_show_devname(struct seq_file *m, struct dentry *root)
182static int afs_show_options(struct seq_file *m, struct dentry *root) 193static int afs_show_options(struct seq_file *m, struct dentry *root)
183{ 194{
184 struct afs_super_info *as = AFS_FS_S(root->d_sb); 195 struct afs_super_info *as = AFS_FS_S(root->d_sb);
196 const char *p = NULL;
185 197
186 if (as->dyn_root) 198 if (as->dyn_root)
187 seq_puts(m, ",dyn"); 199 seq_puts(m, ",dyn");
188 if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) 200 if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags))
189 seq_puts(m, ",autocell"); 201 seq_puts(m, ",autocell");
202 switch (as->flock_mode) {
203 case afs_flock_mode_unset: break;
204 case afs_flock_mode_local: p = "local"; break;
205 case afs_flock_mode_openafs: p = "openafs"; break;
206 case afs_flock_mode_strict: p = "strict"; break;
207 case afs_flock_mode_write: p = "write"; break;
208 }
209 if (p)
210 seq_printf(m, ",flock=%s", p);
211
190 return 0; 212 return 0;
191} 213}
192 214
@@ -315,6 +337,10 @@ static int afs_parse_param(struct fs_context *fc, struct fs_parameter *param)
315 ctx->dyn_root = true; 337 ctx->dyn_root = true;
316 break; 338 break;
317 339
340 case Opt_flock:
341 ctx->flock_mode = result.uint_32;
342 break;
343
318 default: 344 default:
319 return -EINVAL; 345 return -EINVAL;
320 } 346 }
@@ -466,6 +492,7 @@ static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc)
466 as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); 492 as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
467 if (as) { 493 if (as) {
468 as->net_ns = get_net(fc->net_ns); 494 as->net_ns = get_net(fc->net_ns);
495 as->flock_mode = ctx->flock_mode;
469 if (ctx->dyn_root) { 496 if (ctx->dyn_root) {
470 as->dyn_root = true; 497 as->dyn_root = true;
471 } else { 498 } else {
diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c
index 5ea0350dc9dd..055840aa07f6 100644
--- a/fs/afs/yfsclient.c
+++ b/fs/afs/yfsclient.c
@@ -1860,7 +1860,7 @@ int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
1860 yfs_check_req(call, bp); 1860 yfs_check_req(call, bp);
1861 1861
1862 afs_use_fs_server(call, fc->cbi); 1862 afs_use_fs_server(call, fc->cbi);
1863 trace_afs_make_fs_call(call, &vnode->fid); 1863 trace_afs_make_fs_calli(call, &vnode->fid, type);
1864 afs_make_call(&fc->ac, call, GFP_NOFS); 1864 afs_make_call(&fc->ac, call, GFP_NOFS);
1865 return afs_wait_for_call_to_complete(call, &fc->ac); 1865 return afs_wait_for_call_to_complete(call, &fc->ac);
1866} 1866}
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index e81d6a50781f..f1373c29bf7d 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -539,6 +539,41 @@ TRACE_EVENT(afs_make_fs_call,
539 __print_symbolic(__entry->op, afs_fs_operations)) 539 __print_symbolic(__entry->op, afs_fs_operations))
540 ); 540 );
541 541
542TRACE_EVENT(afs_make_fs_calli,
543 TP_PROTO(struct afs_call *call, const struct afs_fid *fid,
544 unsigned int i),
545
546 TP_ARGS(call, fid, i),
547
548 TP_STRUCT__entry(
549 __field(unsigned int, call )
550 __field(unsigned int, i )
551 __field(enum afs_fs_operation, op )
552 __field_struct(struct afs_fid, fid )
553 ),
554
555 TP_fast_assign(
556 __entry->call = call->debug_id;
557 __entry->i = i;
558 __entry->op = call->operation_ID;
559 if (fid) {
560 __entry->fid = *fid;
561 } else {
562 __entry->fid.vid = 0;
563 __entry->fid.vnode = 0;
564 __entry->fid.unique = 0;
565 }
566 ),
567
568 TP_printk("c=%08x %06llx:%06llx:%06x %s i=%u",
569 __entry->call,
570 __entry->fid.vid,
571 __entry->fid.vnode,
572 __entry->fid.unique,
573 __print_symbolic(__entry->op, afs_fs_operations),
574 __entry->i)
575 );
576
542TRACE_EVENT(afs_make_fs_call1, 577TRACE_EVENT(afs_make_fs_call1,
543 TP_PROTO(struct afs_call *call, const struct afs_fid *fid, 578 TP_PROTO(struct afs_call *call, const struct afs_fid *fid,
544 const char *name), 579 const char *name),