diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-10 18:34:42 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-10 18:34:42 -0500 |
| commit | 4b4f8580a4b77126733db8072862793d4deae66a (patch) | |
| tree | 0d6ab49f4fe61ca96fd513b6dfae8be541796320 /include/linux | |
| parent | 872912352c5be930e9568e5f3b6d73107d9f278d (diff) | |
| parent | 8116bf4cb62d337c953cfa5369ef4cf83e73140c (diff) | |
Merge tag 'locks-v3.20-1' of git://git.samba.org/jlayton/linux
Pull file locking related changes #1 from Jeff Layton:
"This patchset contains a fairly major overhaul of how file locks are
tracked within the inode. Rather than a single list, we now create a
per-inode "lock context" that contains individual lists for the file
locks, and a new dedicated spinlock for them.
There are changes in other trees that are based on top of this set so
it may be easiest to pull this in early"
* tag 'locks-v3.20-1' of git://git.samba.org/jlayton/linux:
locks: update comments that refer to inode->i_flock
locks: consolidate NULL i_flctx checks in locks_remove_file
locks: keep a count of locks on the flctx lists
locks: clean up the lm_change prototype
locks: add a dedicated spinlock to protect i_flctx lists
locks: remove i_flock field from struct inode
locks: convert lease handling to file_lock_context
locks: convert posix locks to file_lock_context
locks: move flock locks to file_lock_context
ceph: move spinlocking into ceph_encode_locks_to_buffer and ceph_count_locks
locks: add a new struct file_locking_context pointer to struct inode
locks: have locks_release_file use flock_lock_file to release generic flock locks
locks: add new struct list_head to struct file_lock
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/fs.h | 52 |
1 files changed, 36 insertions, 16 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h index 42efe13077b6..ddd2fa7cefd3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -625,7 +625,7 @@ struct inode { | |||
| 625 | atomic_t i_readcount; /* struct files open RO */ | 625 | atomic_t i_readcount; /* struct files open RO */ |
| 626 | #endif | 626 | #endif |
| 627 | const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ | 627 | const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ |
| 628 | struct file_lock *i_flock; | 628 | struct file_lock_context *i_flctx; |
| 629 | struct address_space i_data; | 629 | struct address_space i_data; |
| 630 | struct list_head i_devices; | 630 | struct list_head i_devices; |
| 631 | union { | 631 | union { |
| @@ -885,6 +885,8 @@ static inline struct file *get_file(struct file *f) | |||
| 885 | /* legacy typedef, should eventually be removed */ | 885 | /* legacy typedef, should eventually be removed */ |
| 886 | typedef void *fl_owner_t; | 886 | typedef void *fl_owner_t; |
| 887 | 887 | ||
| 888 | struct file_lock; | ||
| 889 | |||
| 888 | struct file_lock_operations { | 890 | struct file_lock_operations { |
| 889 | void (*fl_copy_lock)(struct file_lock *, struct file_lock *); | 891 | void (*fl_copy_lock)(struct file_lock *, struct file_lock *); |
| 890 | void (*fl_release_private)(struct file_lock *); | 892 | void (*fl_release_private)(struct file_lock *); |
| @@ -898,7 +900,7 @@ struct lock_manager_operations { | |||
| 898 | void (*lm_notify)(struct file_lock *); /* unblock callback */ | 900 | void (*lm_notify)(struct file_lock *); /* unblock callback */ |
| 899 | int (*lm_grant)(struct file_lock *, int); | 901 | int (*lm_grant)(struct file_lock *, int); |
| 900 | bool (*lm_break)(struct file_lock *); | 902 | bool (*lm_break)(struct file_lock *); |
| 901 | int (*lm_change)(struct file_lock **, int, struct list_head *); | 903 | int (*lm_change)(struct file_lock *, int, struct list_head *); |
| 902 | void (*lm_setup)(struct file_lock *, void **); | 904 | void (*lm_setup)(struct file_lock *, void **); |
| 903 | }; | 905 | }; |
| 904 | 906 | ||
| @@ -923,17 +925,17 @@ int locks_in_grace(struct net *); | |||
| 923 | * FIXME: should we create a separate "struct lock_request" to help distinguish | 925 | * FIXME: should we create a separate "struct lock_request" to help distinguish |
| 924 | * these two uses? | 926 | * these two uses? |
| 925 | * | 927 | * |
| 926 | * The i_flock list is ordered by: | 928 | * The varous i_flctx lists are ordered by: |
| 927 | * | 929 | * |
| 928 | * 1) lock type -- FL_LEASEs first, then FL_FLOCK, and finally FL_POSIX | 930 | * 1) lock owner |
| 929 | * 2) lock owner | 931 | * 2) lock range start |
| 930 | * 3) lock range start | 932 | * 3) lock range end |
| 931 | * 4) lock range end | ||
| 932 | * | 933 | * |
| 933 | * Obviously, the last two criteria only matter for POSIX locks. | 934 | * Obviously, the last two criteria only matter for POSIX locks. |
| 934 | */ | 935 | */ |
| 935 | struct file_lock { | 936 | struct file_lock { |
| 936 | struct file_lock *fl_next; /* singly linked list for this inode */ | 937 | struct file_lock *fl_next; /* singly linked list for this inode */ |
| 938 | struct list_head fl_list; /* link into file_lock_context */ | ||
| 937 | struct hlist_node fl_link; /* node in global lists */ | 939 | struct hlist_node fl_link; /* node in global lists */ |
| 938 | struct list_head fl_block; /* circular list of blocked processes */ | 940 | struct list_head fl_block; /* circular list of blocked processes */ |
| 939 | fl_owner_t fl_owner; | 941 | fl_owner_t fl_owner; |
| @@ -964,6 +966,16 @@ struct file_lock { | |||
| 964 | } fl_u; | 966 | } fl_u; |
| 965 | }; | 967 | }; |
| 966 | 968 | ||
| 969 | struct file_lock_context { | ||
| 970 | spinlock_t flc_lock; | ||
| 971 | struct list_head flc_flock; | ||
| 972 | struct list_head flc_posix; | ||
| 973 | struct list_head flc_lease; | ||
| 974 | int flc_flock_cnt; | ||
| 975 | int flc_posix_cnt; | ||
| 976 | int flc_lease_cnt; | ||
| 977 | }; | ||
| 978 | |||
| 967 | /* The following constant reflects the upper bound of the file/locking space */ | 979 | /* The following constant reflects the upper bound of the file/locking space */ |
| 968 | #ifndef OFFSET_MAX | 980 | #ifndef OFFSET_MAX |
| 969 | #define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1))) | 981 | #define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1))) |
| @@ -990,6 +1002,7 @@ extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg); | |||
| 990 | extern int fcntl_getlease(struct file *filp); | 1002 | extern int fcntl_getlease(struct file *filp); |
| 991 | 1003 | ||
| 992 | /* fs/locks.c */ | 1004 | /* fs/locks.c */ |
| 1005 | void locks_free_lock_context(struct file_lock_context *ctx); | ||
| 993 | void locks_free_lock(struct file_lock *fl); | 1006 | void locks_free_lock(struct file_lock *fl); |
| 994 | extern void locks_init_lock(struct file_lock *); | 1007 | extern void locks_init_lock(struct file_lock *); |
| 995 | extern struct file_lock * locks_alloc_lock(void); | 1008 | extern struct file_lock * locks_alloc_lock(void); |
| @@ -1010,7 +1023,7 @@ extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int t | |||
| 1010 | extern void lease_get_mtime(struct inode *, struct timespec *time); | 1023 | extern void lease_get_mtime(struct inode *, struct timespec *time); |
| 1011 | extern int generic_setlease(struct file *, long, struct file_lock **, void **priv); | 1024 | extern int generic_setlease(struct file *, long, struct file_lock **, void **priv); |
| 1012 | extern int vfs_setlease(struct file *, long, struct file_lock **, void **); | 1025 | extern int vfs_setlease(struct file *, long, struct file_lock **, void **); |
| 1013 | extern int lease_modify(struct file_lock **, int, struct list_head *); | 1026 | extern int lease_modify(struct file_lock *, int, struct list_head *); |
| 1014 | #else /* !CONFIG_FILE_LOCKING */ | 1027 | #else /* !CONFIG_FILE_LOCKING */ |
| 1015 | static inline int fcntl_getlk(struct file *file, unsigned int cmd, | 1028 | static inline int fcntl_getlk(struct file *file, unsigned int cmd, |
| 1016 | struct flock __user *user) | 1029 | struct flock __user *user) |
| @@ -1047,6 +1060,11 @@ static inline int fcntl_getlease(struct file *filp) | |||
| 1047 | return F_UNLCK; | 1060 | return F_UNLCK; |
| 1048 | } | 1061 | } |
| 1049 | 1062 | ||
| 1063 | static inline void | ||
| 1064 | locks_free_lock_context(struct file_lock_context *ctx) | ||
| 1065 | { | ||
| 1066 | } | ||
| 1067 | |||
| 1050 | static inline void locks_init_lock(struct file_lock *fl) | 1068 | static inline void locks_init_lock(struct file_lock *fl) |
| 1051 | { | 1069 | { |
| 1052 | return; | 1070 | return; |
| @@ -1137,7 +1155,7 @@ static inline int vfs_setlease(struct file *filp, long arg, | |||
| 1137 | return -EINVAL; | 1155 | return -EINVAL; |
| 1138 | } | 1156 | } |
| 1139 | 1157 | ||
| 1140 | static inline int lease_modify(struct file_lock **before, int arg, | 1158 | static inline int lease_modify(struct file_lock *fl, int arg, |
| 1141 | struct list_head *dispose) | 1159 | struct list_head *dispose) |
| 1142 | { | 1160 | { |
| 1143 | return -EINVAL; | 1161 | return -EINVAL; |
| @@ -1959,7 +1977,7 @@ static inline int locks_verify_truncate(struct inode *inode, | |||
| 1959 | struct file *filp, | 1977 | struct file *filp, |
| 1960 | loff_t size) | 1978 | loff_t size) |
| 1961 | { | 1979 | { |
| 1962 | if (inode->i_flock && mandatory_lock(inode)) | 1980 | if (inode->i_flctx && mandatory_lock(inode)) |
| 1963 | return locks_mandatory_area( | 1981 | return locks_mandatory_area( |
| 1964 | FLOCK_VERIFY_WRITE, inode, filp, | 1982 | FLOCK_VERIFY_WRITE, inode, filp, |
| 1965 | size < inode->i_size ? size : inode->i_size, | 1983 | size < inode->i_size ? size : inode->i_size, |
| @@ -1973,11 +1991,12 @@ static inline int break_lease(struct inode *inode, unsigned int mode) | |||
| 1973 | { | 1991 | { |
| 1974 | /* | 1992 | /* |
| 1975 | * Since this check is lockless, we must ensure that any refcounts | 1993 | * Since this check is lockless, we must ensure that any refcounts |
| 1976 | * taken are done before checking inode->i_flock. Otherwise, we could | 1994 | * taken are done before checking i_flctx->flc_lease. Otherwise, we |
| 1977 | * end up racing with tasks trying to set a new lease on this file. | 1995 | * could end up racing with tasks trying to set a new lease on this |
| 1996 | * file. | ||
| 1978 | */ | 1997 | */ |
| 1979 | smp_mb(); | 1998 | smp_mb(); |
| 1980 | if (inode->i_flock) | 1999 | if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) |
| 1981 | return __break_lease(inode, mode, FL_LEASE); | 2000 | return __break_lease(inode, mode, FL_LEASE); |
| 1982 | return 0; | 2001 | return 0; |
| 1983 | } | 2002 | } |
| @@ -1986,11 +2005,12 @@ static inline int break_deleg(struct inode *inode, unsigned int mode) | |||
| 1986 | { | 2005 | { |
| 1987 | /* | 2006 | /* |
| 1988 | * Since this check is lockless, we must ensure that any refcounts | 2007 | * Since this check is lockless, we must ensure that any refcounts |
| 1989 | * taken are done before checking inode->i_flock. Otherwise, we could | 2008 | * taken are done before checking i_flctx->flc_lease. Otherwise, we |
| 1990 | * end up racing with tasks trying to set a new lease on this file. | 2009 | * could end up racing with tasks trying to set a new lease on this |
| 2010 | * file. | ||
| 1991 | */ | 2011 | */ |
| 1992 | smp_mb(); | 2012 | smp_mb(); |
| 1993 | if (inode->i_flock) | 2013 | if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) |
| 1994 | return __break_lease(inode, mode, FL_DELEG); | 2014 | return __break_lease(inode, mode, FL_DELEG); |
| 1995 | return 0; | 2015 | return 0; |
| 1996 | } | 2016 | } |
