aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/Locking16
-rw-r--r--fs/lockd/svclock.c12
-rw-r--r--fs/locks.c12
-rw-r--r--include/linux/fs.h1
4 files changed, 34 insertions, 7 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index c2963a74fbc3..2db7c9e492e9 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -349,6 +349,7 @@ fl_release_private: maybe no
349----------------------- lock_manager_operations --------------------------- 349----------------------- lock_manager_operations ---------------------------
350prototypes: 350prototypes:
351 int (*lm_compare_owner)(struct file_lock *, struct file_lock *); 351 int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
352 unsigned long (*lm_owner_key)(struct file_lock *);
352 void (*lm_notify)(struct file_lock *); /* unblock callback */ 353 void (*lm_notify)(struct file_lock *); /* unblock callback */
353 int (*lm_grant)(struct file_lock *, struct file_lock *, int); 354 int (*lm_grant)(struct file_lock *, struct file_lock *, int);
354 void (*lm_break)(struct file_lock *); /* break_lease callback */ 355 void (*lm_break)(struct file_lock *); /* break_lease callback */
@@ -358,16 +359,21 @@ locking rules:
358 359
359 inode->i_lock file_lock_lock may block 360 inode->i_lock file_lock_lock may block
360lm_compare_owner: yes[1] maybe no 361lm_compare_owner: yes[1] maybe no
362lm_owner_key yes[1] yes no
361lm_notify: yes yes no 363lm_notify: yes yes no
362lm_grant: no no no 364lm_grant: no no no
363lm_break: yes no no 365lm_break: yes no no
364lm_change yes no no 366lm_change yes no no
365 367
366[1]: ->lm_compare_owner is generally called with *an* inode->i_lock held. It 368[1]: ->lm_compare_owner and ->lm_owner_key are generally called with
367may not be the i_lock of the inode for either file_lock being compared! This is 369*an* inode->i_lock held. It may not be the i_lock of the inode
368the case with deadlock detection, since the code has to chase down the owners 370associated with either file_lock argument! This is the case with deadlock
369of locks that may be entirely unrelated to the one on which the lock is being 371detection, since the code has to chase down the owners of locks that may
370acquired. When doing a search for deadlocks, the file_lock_lock is also held. 372be entirely unrelated to the one on which the lock is being acquired.
373For deadlock detection however, the file_lock_lock is also held. The
374fact that these locks are held ensures that the file_locks do not
375disappear out from under you while doing the comparison or generating an
376owner key.
371 377
372--------------------------- buffer_head ----------------------------------- 378--------------------------- buffer_head -----------------------------------
373prototypes: 379prototypes:
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index a469098682c4..067778b0ccc9 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -744,8 +744,20 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
744 return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid; 744 return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid;
745} 745}
746 746
747/*
748 * Since NLM uses two "keys" for tracking locks, we need to hash them down
749 * to one for the blocked_hash. Here, we're just xor'ing the host address
750 * with the pid in order to create a key value for picking a hash bucket.
751 */
752static unsigned long
753nlmsvc_owner_key(struct file_lock *fl)
754{
755 return (unsigned long)fl->fl_owner ^ (unsigned long)fl->fl_pid;
756}
757
747const struct lock_manager_operations nlmsvc_lock_operations = { 758const struct lock_manager_operations nlmsvc_lock_operations = {
748 .lm_compare_owner = nlmsvc_same_owner, 759 .lm_compare_owner = nlmsvc_same_owner,
760 .lm_owner_key = nlmsvc_owner_key,
749 .lm_notify = nlmsvc_notify_blocked, 761 .lm_notify = nlmsvc_notify_blocked,
750 .lm_grant = nlmsvc_grant_deferred, 762 .lm_grant = nlmsvc_grant_deferred,
751}; 763};
diff --git a/fs/locks.c b/fs/locks.c
index 71d847cbbb63..6242e0b1c69c 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -521,10 +521,18 @@ locks_delete_global_locks(struct file_lock *fl)
521 spin_unlock(&file_lock_lock); 521 spin_unlock(&file_lock_lock);
522} 522}
523 523
524static unsigned long
525posix_owner_key(struct file_lock *fl)
526{
527 if (fl->fl_lmops && fl->fl_lmops->lm_owner_key)
528 return fl->fl_lmops->lm_owner_key(fl);
529 return (unsigned long)fl->fl_owner;
530}
531
524static inline void 532static inline void
525locks_insert_global_blocked(struct file_lock *waiter) 533locks_insert_global_blocked(struct file_lock *waiter)
526{ 534{
527 hash_add(blocked_hash, &waiter->fl_link, (unsigned long)waiter->fl_owner); 535 hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter));
528} 536}
529 537
530static inline void 538static inline void
@@ -757,7 +765,7 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
757{ 765{
758 struct file_lock *fl; 766 struct file_lock *fl;
759 767
760 hash_for_each_possible(blocked_hash, fl, fl_link, (unsigned long)block_fl->fl_owner) { 768 hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) {
761 if (posix_same_owner(fl, block_fl)) 769 if (posix_same_owner(fl, block_fl))
762 return fl->fl_next; 770 return fl->fl_next;
763 } 771 }
diff --git a/include/linux/fs.h b/include/linux/fs.h
index fab064a3b65f..a137a73fc1fe 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -908,6 +908,7 @@ struct file_lock_operations {
908 908
909struct lock_manager_operations { 909struct lock_manager_operations {
910 int (*lm_compare_owner)(struct file_lock *, struct file_lock *); 910 int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
911 unsigned long (*lm_owner_key)(struct file_lock *);
911 void (*lm_notify)(struct file_lock *); /* unblock callback */ 912 void (*lm_notify)(struct file_lock *); /* unblock callback */
912 int (*lm_grant)(struct file_lock *, struct file_lock *, int); 913 int (*lm_grant)(struct file_lock *, struct file_lock *, int);
913 void (*lm_break)(struct file_lock *); 914 void (*lm_break)(struct file_lock *);