diff mbox

[v1,009/104] locks: add file_has_lease

Message ID 1403189450-18729-10-git-send-email-jlayton@primarydata.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jeff Layton June 19, 2014, 2:49 p.m. UTC
Add a function that can tell us whether a file description has had a
lease set on it.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/locks.c         | 26 ++++++++++++++++++++++++++
 include/linux/fs.h |  6 ++++++
 2 files changed, 32 insertions(+)

Comments

Christoph Hellwig June 23, 2014, 4:12 p.m. UTC | #1
On Thu, Jun 19, 2014 at 10:49:15AM -0400, Jeff Layton wrote:
> Add a function that can tell us whether a file description has had a
> lease set on it.

The code looks good, but how is this information useful given that it
will be stable as soon as i_lock is dropped?

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jeff Layton June 23, 2014, 4:48 p.m. UTC | #2
On Mon, 23 Jun 2014 09:12:54 -0700
Christoph Hellwig <hch@infradead.org> wrote:

> On Thu, Jun 19, 2014 at 10:49:15AM -0400, Jeff Layton wrote:
> > Add a function that can tell us whether a file description has had a
> > lease set on it.
> 
> The code looks good, but how is this information useful given that it
> will be stable as soon as i_lock is dropped?
> 

The next patch is what uses it. I can squash the two together, but I
figured it was best to keep them separate since we're touching two
different subsystems here.

The basic idea here is to avoid calling vfs_setlease under a spinlock.
The next patch does that and then takes the spinlocks and hash the
delegation once the lease is set.

Problem: what if the delegation got broken before we could hash it?

The workqueue job that's queued by break_deleg will take the state_lock
spinlock before it can unhash the delegation. So, we take the
state_lock and then call file_has_lease. If the lease is still present
then we know that it hasn't been (and won't be) broken before we could
hash it.
diff mbox

Patch

diff --git a/fs/locks.c b/fs/locks.c
index da57c9b7e844..402169f95502 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1308,6 +1308,32 @@  static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
 }
 
 /**
+ * file_has_lease - does the given file have a lease set on it?
+ * @file: struct file on which we want to check the lease
+ *
+ * Returns true if a lease was is set on the given file description,
+ * false otherwise.
+ */
+bool
+file_has_lease(struct file *file)
+{
+	bool ret = false;
+	struct inode *inode = file_inode(file);
+	struct file_lock *fl;
+
+	spin_lock(&inode->i_lock);
+	for (fl = inode->i_flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
+		if (fl->fl_file == file) {
+			ret = true;
+			break;
+		}
+	}
+	spin_unlock(&inode->i_lock);
+	return ret;
+}
+EXPORT_SYMBOL(file_has_lease);
+
+/**
  *	__break_lease	-	revoke all outstanding leases on file
  *	@inode: the inode of the file to return
  *	@mode: O_RDONLY: break only write leases; O_WRONLY or O_RDWR:
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 338e6f758c6d..7937523c21ca 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -953,6 +953,7 @@  extern int vfs_test_lock(struct file *, struct file_lock *);
 extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
 extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
+extern bool file_has_lease(struct file *file);
 extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
 extern int generic_setlease(struct file *, long, struct file_lock **);
@@ -1064,6 +1065,11 @@  static inline int flock_lock_file_wait(struct file *filp,
 	return -ENOLCK;
 }
 
+static inline bool file_has_lease(struct file *file)
+{
+	return false;
+}
+
 static inline int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
 {
 	return 0;