From 6dee60f69d48fcef021b4b53b3431797ec440764 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Jan 2015 15:05:54 -0500 Subject: locks: add new struct list_head to struct file_lock ...that we can use to queue file_locks to per-ctx list_heads. Go ahead and convert locks_delete_lock and locks_dispose_list to use it instead of the fl_block list. Signed-off-by: Jeff Layton Acked-by: Christoph Hellwig --- include/linux/fs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 42efe13077b6..cd6818115162 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -934,6 +934,7 @@ int locks_in_grace(struct net *); */ struct file_lock { struct file_lock *fl_next; /* singly linked list for this inode */ + struct list_head fl_list; /* link into file_lock_context */ struct hlist_node fl_link; /* node in global lists */ struct list_head fl_block; /* circular list of blocked processes */ fl_owner_t fl_owner; -- cgit v1.2.3 From 4a075e39c86490cc0f0c10ac6abe3592d1689463 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Jan 2015 15:05:54 -0500 Subject: locks: add a new struct file_locking_context pointer to struct inode The current scheme of using the i_flock list is really difficult to manage. There is also a legitimate desire for a per-inode spinlock to manage these lists that isn't the i_lock. Start conversion to a new scheme to eventually replace the old i_flock list with a new "file_lock_context" object. We start by adding a new i_flctx to struct inode. For now, it lives in parallel with i_flock list, but will eventually replace it. The idea is to allocate a structure to sit in that pointer and act as a locus for all things file locking. We allocate a file_lock_context for an inode when the first lock is added to it, and it's only freed when the inode is freed. We use the i_lock to protect the assignment, but afterward it should mostly be accessed locklessly. Signed-off-by: Jeff Layton Acked-by: Christoph Hellwig --- include/linux/fs.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index cd6818115162..dec0d38b05de 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -626,6 +626,7 @@ struct inode { #endif const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ struct file_lock *i_flock; + struct file_lock_context *i_flctx; struct address_space i_data; struct list_head i_devices; union { @@ -965,6 +966,10 @@ struct file_lock { } fl_u; }; +struct file_lock_context { + struct list_head flc_flock; +}; + /* The following constant reflects the upper bound of the file/locking space */ #ifndef OFFSET_MAX #define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1))) @@ -991,6 +996,7 @@ extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg); extern int fcntl_getlease(struct file *filp); /* fs/locks.c */ +void locks_free_lock_context(struct file_lock_context *ctx); void locks_free_lock(struct file_lock *fl); extern void locks_init_lock(struct file_lock *); extern struct file_lock * locks_alloc_lock(void); @@ -1048,6 +1054,11 @@ static inline int fcntl_getlease(struct file *filp) return F_UNLCK; } +static inline void +locks_free_lock_context(struct file_lock_context *ctx) +{ +} + static inline void locks_init_lock(struct file_lock *fl) { return; -- cgit v1.2.3 From bd61e0a9c852de2d705b6f1bb2cc54c5774db570 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Jan 2015 15:05:55 -0500 Subject: locks: convert posix locks to file_lock_context Signed-off-by: Jeff Layton Acked-by: Christoph Hellwig --- include/linux/fs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index dec0d38b05de..571f113588e9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -968,6 +968,7 @@ struct file_lock { struct file_lock_context { struct list_head flc_flock; + struct list_head flc_posix; }; /* The following constant reflects the upper bound of the file/locking space */ @@ -1971,7 +1972,7 @@ static inline int locks_verify_truncate(struct inode *inode, struct file *filp, loff_t size) { - if (inode->i_flock && mandatory_lock(inode)) + if (inode->i_flctx && mandatory_lock(inode)) return locks_mandatory_area( FLOCK_VERIFY_WRITE, inode, filp, size < inode->i_size ? size : inode->i_size, -- cgit v1.2.3 From 8634b51f6ca298fb8b07aa4847340764903533ab Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Jan 2015 15:05:55 -0500 Subject: locks: convert lease handling to file_lock_context Signed-off-by: Jeff Layton Acked-by: Christoph Hellwig --- include/linux/fs.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 571f113588e9..2ddec3cf81b9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -969,6 +969,7 @@ struct file_lock { struct file_lock_context { struct list_head flc_flock; struct list_head flc_posix; + struct list_head flc_lease; }; /* The following constant reflects the upper bound of the file/locking space */ @@ -1990,7 +1991,7 @@ static inline int break_lease(struct inode *inode, unsigned int mode) * end up racing with tasks trying to set a new lease on this file. */ smp_mb(); - if (inode->i_flock) + if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) return __break_lease(inode, mode, FL_LEASE); return 0; } @@ -2003,7 +2004,7 @@ static inline int break_deleg(struct inode *inode, unsigned int mode) * end up racing with tasks trying to set a new lease on this file. */ smp_mb(); - if (inode->i_flock) + if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) return __break_lease(inode, mode, FL_DELEG); return 0; } -- cgit v1.2.3 From a7231a97467d5a0c36f82f581c76c12c034e4b80 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Jan 2015 15:05:56 -0500 Subject: locks: remove i_flock field from struct inode Nothing uses it anymore. Also add a forward declaration for struct file_lock to silence some compiler warnings that the removal triggers. Signed-off-by: Jeff Layton Acked-by: Christoph Hellwig --- include/linux/fs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 2ddec3cf81b9..ce0873af0b97 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -625,7 +625,6 @@ struct inode { atomic_t i_readcount; /* struct files open RO */ #endif const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ - struct file_lock *i_flock; struct file_lock_context *i_flctx; struct address_space i_data; struct list_head i_devices; @@ -886,6 +885,8 @@ static inline struct file *get_file(struct file *f) /* legacy typedef, should eventually be removed */ typedef void *fl_owner_t; +struct file_lock; + struct file_lock_operations { void (*fl_copy_lock)(struct file_lock *, struct file_lock *); void (*fl_release_private)(struct file_lock *); -- cgit v1.2.3 From 6109c85037e53443f29fd39c0de69f578a1cf285 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Jan 2015 15:05:57 -0500 Subject: locks: add a dedicated spinlock to protect i_flctx lists We can now add a dedicated spinlock without expanding struct inode. Change to using that to protect the various i_flctx lists. Signed-off-by: Jeff Layton Acked-by: Christoph Hellwig --- include/linux/fs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index ce0873af0b97..32eafa9b5c9f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -968,6 +968,7 @@ struct file_lock { }; struct file_lock_context { + spinlock_t flc_lock; struct list_head flc_flock; struct list_head flc_posix; struct list_head flc_lease; -- cgit v1.2.3 From 7448cc37b1a6b620d948aaee3bb30960c06d5d5d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Jan 2015 15:05:57 -0500 Subject: locks: clean up the lm_change prototype Now that we use standard list_heads for tracking leases, we can have lm_change take a pointer to the lease to be modified instead of a double pointer. Signed-off-by: Jeff Layton Acked-by: Christoph Hellwig --- include/linux/fs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 32eafa9b5c9f..94e706a0a408 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -900,7 +900,7 @@ struct lock_manager_operations { void (*lm_notify)(struct file_lock *); /* unblock callback */ int (*lm_grant)(struct file_lock *, int); bool (*lm_break)(struct file_lock *); - int (*lm_change)(struct file_lock **, int, struct list_head *); + int (*lm_change)(struct file_lock *, int, struct list_head *); void (*lm_setup)(struct file_lock *, void **); }; @@ -1021,7 +1021,7 @@ extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int t extern void lease_get_mtime(struct inode *, struct timespec *time); extern int generic_setlease(struct file *, long, struct file_lock **, void **priv); extern int vfs_setlease(struct file *, long, struct file_lock **, void **); -extern int lease_modify(struct file_lock **, int, struct list_head *); +extern int lease_modify(struct file_lock *, int, struct list_head *); #else /* !CONFIG_FILE_LOCKING */ static inline int fcntl_getlk(struct file *file, unsigned int cmd, struct flock __user *user) @@ -1153,7 +1153,7 @@ static inline int vfs_setlease(struct file *filp, long arg, return -EINVAL; } -static inline int lease_modify(struct file_lock **before, int arg, +static inline int lease_modify(struct file_lock *fl, int arg, struct list_head *dispose) { return -EINVAL; -- cgit v1.2.3 From 9bd0f45b7037fcfa8b575c7e27d0431d6e6dc3bb Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Jan 2015 15:05:57 -0500 Subject: locks: keep a count of locks on the flctx lists This makes things a bit more efficient in the cifs and ceph lock pushing code. Signed-off-by: Jeff Layton Acked-by: Christoph Hellwig --- include/linux/fs.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 94e706a0a408..f87cb2f03103 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -972,6 +972,9 @@ struct file_lock_context { struct list_head flc_flock; struct list_head flc_posix; struct list_head flc_lease; + int flc_flock_cnt; + int flc_posix_cnt; + int flc_lease_cnt; }; /* The following constant reflects the upper bound of the file/locking space */ -- cgit v1.2.3 From 8116bf4cb62d337c953cfa5369ef4cf83e73140c Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 21 Jan 2015 20:44:01 -0500 Subject: locks: update comments that refer to inode->i_flock Signed-off-by: Jeff Layton --- include/linux/fs.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index f87cb2f03103..ddd2fa7cefd3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -925,12 +925,11 @@ int locks_in_grace(struct net *); * FIXME: should we create a separate "struct lock_request" to help distinguish * these two uses? * - * The i_flock list is ordered by: + * The varous i_flctx lists are ordered by: * - * 1) lock type -- FL_LEASEs first, then FL_FLOCK, and finally FL_POSIX - * 2) lock owner - * 3) lock range start - * 4) lock range end + * 1) lock owner + * 2) lock range start + * 3) lock range end * * Obviously, the last two criteria only matter for POSIX locks. */ @@ -1992,8 +1991,9 @@ static inline int break_lease(struct inode *inode, unsigned int mode) { /* * Since this check is lockless, we must ensure that any refcounts - * taken are done before checking inode->i_flock. Otherwise, we could - * end up racing with tasks trying to set a new lease on this file. + * taken are done before checking i_flctx->flc_lease. Otherwise, we + * could end up racing with tasks trying to set a new lease on this + * file. */ smp_mb(); if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) @@ -2005,8 +2005,9 @@ static inline int break_deleg(struct inode *inode, unsigned int mode) { /* * Since this check is lockless, we must ensure that any refcounts - * taken are done before checking inode->i_flock. Otherwise, we could - * end up racing with tasks trying to set a new lease on this file. + * taken are done before checking i_flctx->flc_lease. Otherwise, we + * could end up racing with tasks trying to set a new lease on this + * file. */ smp_mb(); if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) -- cgit v1.2.3