Commit 73fa58dc authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull file locking updates from Jeff Layton:
 "The main change here is to add the new locks_inode_context helper, and
  convert all of the places that dereference inode->i_flctx directly to
  use that instead.

  There is a new helper to indicate whether any locks are held on an
  inode. This is mostly for Ceph but may be usable elsewhere too.

  Andi Kleen requested that we print the PID when the LOCK_MAND warning
  fires, to help track down applications trying to use it.

  Finally, we added some new warnings to some of the file locking
  functions that fire when the ->fl_file and filp arguments differ. This
  helped us find some long-standing bugs in lockd. Patches for those are
  in Chuck Lever's tree and should be in his v6.2 PR. After that patch,
  people using NFSv2/v3 locking may see some warnings fire until those
  go in.

  Happy Holidays!"

* tag 'locks-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton/linux:
  Add process name and pid to locks warning
  nfsd: use locks_inode_context helper
  nfs: use locks_inode_context helper
  lockd: use locks_inode_context helper
  ksmbd: use locks_inode_context helper
  cifs: use locks_inode_context helper
  ceph: use locks_inode_context helper
  filelock: add a new locks_inode_context accessor function
  filelock: new helper: vfs_inode_has_locks
  filelock: WARN_ON_ONCE when ->fl_file and filp don't match
parents 7fc03505 f2f2494c
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -364,7 +364,7 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
	*fcntl_count = 0;
	*fcntl_count = 0;
	*flock_count = 0;
	*flock_count = 0;


	ctx = inode->i_flctx;
	ctx = locks_inode_context(inode);
	if (ctx) {
	if (ctx) {
		spin_lock(&ctx->flc_lock);
		spin_lock(&ctx->flc_lock);
		list_for_each_entry(lock, &ctx->flc_posix, fl_list)
		list_for_each_entry(lock, &ctx->flc_posix, fl_list)
@@ -418,7 +418,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
				int num_fcntl_locks, int num_flock_locks)
				int num_fcntl_locks, int num_flock_locks)
{
{
	struct file_lock *lock;
	struct file_lock *lock;
	struct file_lock_context *ctx = inode->i_flctx;
	struct file_lock_context *ctx = locks_inode_context(inode);
	int err = 0;
	int err = 0;
	int seen_fcntl = 0;
	int seen_fcntl = 0;
	int seen_flock = 0;
	int seen_flock = 0;
+1 −1
Original line number Original line Diff line number Diff line
@@ -1413,7 +1413,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
	struct inode *inode = d_inode(cfile->dentry);
	struct inode *inode = d_inode(cfile->dentry);
	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
	struct file_lock *flock;
	struct file_lock *flock;
	struct file_lock_context *flctx = inode->i_flctx;
	struct file_lock_context *flctx = locks_inode_context(inode);
	unsigned int count = 0, i;
	unsigned int count = 0, i;
	int rc = 0, xid, type;
	int rc = 0, xid, type;
	struct list_head locks_to_send, *el;
	struct list_head locks_to_send, *el;
+1 −1
Original line number Original line Diff line number Diff line
@@ -321,7 +321,7 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end,
			    unsigned char type)
			    unsigned char type)
{
{
	struct file_lock *flock;
	struct file_lock *flock;
	struct file_lock_context *ctx = file_inode(filp)->i_flctx;
	struct file_lock_context *ctx = locks_inode_context(file_inode(filp));
	int error = 0;
	int error = 0;


	if (!ctx || list_empty_careful(&ctx->flc_posix))
	if (!ctx || list_empty_careful(&ctx->flc_posix))
+2 −2
Original line number Original line Diff line number Diff line
@@ -207,7 +207,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
{
{
	struct inode	 *inode = nlmsvc_file_inode(file);
	struct inode	 *inode = nlmsvc_file_inode(file);
	struct file_lock *fl;
	struct file_lock *fl;
	struct file_lock_context *flctx = inode->i_flctx;
	struct file_lock_context *flctx = locks_inode_context(inode);
	struct nlm_host	 *lockhost;
	struct nlm_host	 *lockhost;


	if (!flctx || list_empty_careful(&flctx->flc_posix))
	if (!flctx || list_empty_careful(&flctx->flc_posix))
@@ -262,7 +262,7 @@ nlm_file_inuse(struct nlm_file *file)
{
{
	struct inode	 *inode = nlmsvc_file_inode(file);
	struct inode	 *inode = nlmsvc_file_inode(file);
	struct file_lock *fl;
	struct file_lock *fl;
	struct file_lock_context *flctx = inode->i_flctx;
	struct file_lock_context *flctx = locks_inode_context(inode);


	if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
	if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
		return 1;
		return 1;
+38 −12
Original line number Original line Diff line number Diff line
@@ -175,7 +175,7 @@ locks_get_lock_context(struct inode *inode, int type)
	struct file_lock_context *ctx;
	struct file_lock_context *ctx;


	/* paired with cmpxchg() below */
	/* paired with cmpxchg() below */
	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (likely(ctx) || type == F_UNLCK)
	if (likely(ctx) || type == F_UNLCK)
		goto out;
		goto out;


@@ -194,7 +194,7 @@ locks_get_lock_context(struct inode *inode, int type)
	 */
	 */
	if (cmpxchg(&inode->i_flctx, NULL, ctx)) {
	if (cmpxchg(&inode->i_flctx, NULL, ctx)) {
		kmem_cache_free(flctx_cache, ctx);
		kmem_cache_free(flctx_cache, ctx);
		ctx = smp_load_acquire(&inode->i_flctx);
		ctx = locks_inode_context(inode);
	}
	}
out:
out:
	trace_locks_get_lock_context(inode, type, ctx);
	trace_locks_get_lock_context(inode, type, ctx);
@@ -247,7 +247,7 @@ locks_check_ctx_file_list(struct file *filp, struct list_head *list,
void
void
locks_free_lock_context(struct inode *inode)
locks_free_lock_context(struct inode *inode)
{
{
	struct file_lock_context *ctx = inode->i_flctx;
	struct file_lock_context *ctx = locks_inode_context(inode);


	if (unlikely(ctx)) {
	if (unlikely(ctx)) {
		locks_check_ctx_lists(inode);
		locks_check_ctx_lists(inode);
@@ -891,7 +891,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
	void *owner;
	void *owner;
	void (*func)(void);
	void (*func)(void);


	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx || list_empty_careful(&ctx->flc_posix)) {
	if (!ctx || list_empty_careful(&ctx->flc_posix)) {
		fl->fl_type = F_UNLCK;
		fl->fl_type = F_UNLCK;
		return;
		return;
@@ -1483,7 +1483,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
	new_fl->fl_flags = type;
	new_fl->fl_flags = type;


	/* typically we will check that ctx is non-NULL before calling */
	/* typically we will check that ctx is non-NULL before calling */
	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx) {
	if (!ctx) {
		WARN_ON_ONCE(1);
		WARN_ON_ONCE(1);
		goto free_lock;
		goto free_lock;
@@ -1588,7 +1588,7 @@ void lease_get_mtime(struct inode *inode, struct timespec64 *time)
	struct file_lock_context *ctx;
	struct file_lock_context *ctx;
	struct file_lock *fl;
	struct file_lock *fl;


	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
		spin_lock(&ctx->flc_lock);
		spin_lock(&ctx->flc_lock);
		fl = list_first_entry_or_null(&ctx->flc_lease,
		fl = list_first_entry_or_null(&ctx->flc_lease,
@@ -1634,7 +1634,7 @@ int fcntl_getlease(struct file *filp)
	int type = F_UNLCK;
	int type = F_UNLCK;
	LIST_HEAD(dispose);
	LIST_HEAD(dispose);


	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
		percpu_down_read(&file_rwsem);
		percpu_down_read(&file_rwsem);
		spin_lock(&ctx->flc_lock);
		spin_lock(&ctx->flc_lock);
@@ -1823,7 +1823,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
	struct file_lock_context *ctx;
	struct file_lock_context *ctx;
	LIST_HEAD(dispose);
	LIST_HEAD(dispose);


	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx) {
	if (!ctx) {
		trace_generic_delete_lease(inode, NULL);
		trace_generic_delete_lease(inode, NULL);
		return error;
		return error;
@@ -2096,7 +2096,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
	 * throw a warning to let people know that they don't actually work.
	 * throw a warning to let people know that they don't actually work.
	 */
	 */
	if (cmd & LOCK_MAND) {
	if (cmd & LOCK_MAND) {
		pr_warn_once("Attempt to set a LOCK_MAND lock via flock(2). This support has been removed and the request ignored.\n");
		pr_warn_once("%s(%d): Attempt to set a LOCK_MAND lock via flock(2). This support has been removed and the request ignored.\n", current->comm, current->pid);
		return 0;
		return 0;
	}
	}


@@ -2146,6 +2146,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
 */
 */
int vfs_test_lock(struct file *filp, struct file_lock *fl)
int vfs_test_lock(struct file *filp, struct file_lock *fl)
{
{
	WARN_ON_ONCE(filp != fl->fl_file);
	if (filp->f_op->lock)
	if (filp->f_op->lock)
		return filp->f_op->lock(filp, F_GETLK, fl);
		return filp->f_op->lock(filp, F_GETLK, fl);
	posix_test_lock(filp, fl);
	posix_test_lock(filp, fl);
@@ -2295,6 +2296,7 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock)
 */
 */
int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
{
{
	WARN_ON_ONCE(filp != fl->fl_file);
	if (filp->f_op->lock)
	if (filp->f_op->lock)
		return filp->f_op->lock(filp, cmd, fl);
		return filp->f_op->lock(filp, cmd, fl);
	else
	else
@@ -2561,7 +2563,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
	 * posix_lock_file().  Another process could be setting a lock on this
	 * 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.
	 * file at the same time, but we wouldn't remove that lock anyway.
	 */
	 */
	ctx =  smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx || list_empty(&ctx->flc_posix))
	if (!ctx || list_empty(&ctx->flc_posix))
		return;
		return;


@@ -2634,7 +2636,7 @@ void locks_remove_file(struct file *filp)
{
{
	struct file_lock_context *ctx;
	struct file_lock_context *ctx;


	ctx = smp_load_acquire(&locks_inode(filp)->i_flctx);
	ctx = locks_inode_context(locks_inode(filp));
	if (!ctx)
	if (!ctx)
		return;
		return;


@@ -2663,12 +2665,36 @@ void locks_remove_file(struct file *filp)
 */
 */
int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
{
{
	WARN_ON_ONCE(filp != fl->fl_file);
	if (filp->f_op->lock)
	if (filp->f_op->lock)
		return filp->f_op->lock(filp, F_CANCELLK, fl);
		return filp->f_op->lock(filp, F_CANCELLK, fl);
	return 0;
	return 0;
}
}
EXPORT_SYMBOL_GPL(vfs_cancel_lock);
EXPORT_SYMBOL_GPL(vfs_cancel_lock);


/**
 * vfs_inode_has_locks - are any file locks held on @inode?
 * @inode: inode to check for locks
 *
 * Return true if there are any FL_POSIX or FL_FLOCK locks currently
 * set on @inode.
 */
bool vfs_inode_has_locks(struct inode *inode)
{
	struct file_lock_context *ctx;
	bool ret;

	ctx = locks_inode_context(inode);
	if (!ctx)
		return false;

	spin_lock(&ctx->flc_lock);
	ret = !list_empty(&ctx->flc_posix) || !list_empty(&ctx->flc_flock);
	spin_unlock(&ctx->flc_lock);
	return ret;
}
EXPORT_SYMBOL_GPL(vfs_inode_has_locks);

#ifdef CONFIG_PROC_FS
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/seq_file.h>
@@ -2839,7 +2865,7 @@ void show_fd_locks(struct seq_file *f,
	struct file_lock_context *ctx;
	struct file_lock_context *ctx;
	int id = 0;
	int id = 0;


	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx)
	if (!ctx)
		return;
		return;


Loading