Commit 11afe9f7 authored by Christoph Hellwig's avatar Christoph Hellwig

fs: add FL_LAYOUT lease type

This (ab-)uses the file locking code to allow filesystems to recall
outstanding pNFS layouts on a file.  This new lease type is similar but
not quite the same as FL_DELEG.  A FL_LAYOUT lease can always be granted,
an a per-filesystem lock (XFS iolock for the initial implementation)
ensures not FL_LAYOUT leases granted when we would need to recall them.

Also included are changes that allow multiple outstanding read
leases of different types on the same file as long as they have a
differnt owner.  This wasn't a problem until now as nfsd never set
FL_LEASE leases, and no one else used FL_DELEG leases, but given that
nfsd will also issues FL_LAYOUT leases we will have to handle it now.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 2ab99ee1
...@@ -137,7 +137,7 @@ ...@@ -137,7 +137,7 @@
#define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX)
#define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK)
#define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG)) #define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
#define IS_OFDLCK(fl) (fl->fl_flags & FL_OFDLCK) #define IS_OFDLCK(fl) (fl->fl_flags & FL_OFDLCK)
static bool lease_breaking(struct file_lock *fl) static bool lease_breaking(struct file_lock *fl)
...@@ -1371,6 +1371,8 @@ static void time_out_leases(struct inode *inode, struct list_head *dispose) ...@@ -1371,6 +1371,8 @@ static void time_out_leases(struct inode *inode, struct list_head *dispose)
static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker) static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
{ {
if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT))
return false;
if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE))
return false; return false;
return locks_conflict(breaker, lease); return locks_conflict(breaker, lease);
...@@ -1594,11 +1596,14 @@ int fcntl_getlease(struct file *filp) ...@@ -1594,11 +1596,14 @@ int fcntl_getlease(struct file *filp)
* conflict with the lease we're trying to set. * conflict with the lease we're trying to set.
*/ */
static int static int
check_conflicting_open(const struct dentry *dentry, const long arg) check_conflicting_open(const struct dentry *dentry, const long arg, int flags)
{ {
int ret = 0; int ret = 0;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
if (flags & FL_LAYOUT)
return 0;
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
return -EAGAIN; return -EAGAIN;
...@@ -1647,7 +1652,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr ...@@ -1647,7 +1652,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
spin_lock(&ctx->flc_lock); spin_lock(&ctx->flc_lock);
time_out_leases(inode, &dispose); time_out_leases(inode, &dispose);
error = check_conflicting_open(dentry, arg); error = check_conflicting_open(dentry, arg, lease->fl_flags);
if (error) if (error)
goto out; goto out;
...@@ -1703,7 +1708,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr ...@@ -1703,7 +1708,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
* precedes these checks. * precedes these checks.
*/ */
smp_mb(); smp_mb();
error = check_conflicting_open(dentry, arg); error = check_conflicting_open(dentry, arg, lease->fl_flags);
if (error) { if (error) {
locks_unlink_lock_ctx(lease, &ctx->flc_lease_cnt); locks_unlink_lock_ctx(lease, &ctx->flc_lease_cnt);
goto out; goto out;
...@@ -1787,6 +1792,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp, ...@@ -1787,6 +1792,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
return -ENOLCK; return -ENOLCK;
} }
return generic_add_lease(filp, arg, flp, priv); return generic_add_lease(filp, arg, flp, priv);
default: default:
return -EINVAL; return -EINVAL;
......
...@@ -875,6 +875,7 @@ static inline struct file *get_file(struct file *f) ...@@ -875,6 +875,7 @@ static inline struct file *get_file(struct file *f)
#define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ #define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */
#define FL_UNLOCK_PENDING 512 /* Lease is being broken */ #define FL_UNLOCK_PENDING 512 /* Lease is being broken */
#define FL_OFDLCK 1024 /* lock is "owned" by struct file */ #define FL_OFDLCK 1024 /* lock is "owned" by struct file */
#define FL_LAYOUT 2048 /* outstanding pNFS layout */
/* /*
* Special return value from posix_lock_file() and vfs_lock_file() for * Special return value from posix_lock_file() and vfs_lock_file() for
...@@ -2037,6 +2038,16 @@ static inline int break_deleg_wait(struct inode **delegated_inode) ...@@ -2037,6 +2038,16 @@ static inline int break_deleg_wait(struct inode **delegated_inode)
return ret; return ret;
} }
static inline int break_layout(struct inode *inode, bool wait)
{
smp_mb();
if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease))
return __break_lease(inode,
wait ? O_WRONLY : O_WRONLY | O_NONBLOCK,
FL_LAYOUT);
return 0;
}
#else /* !CONFIG_FILE_LOCKING */ #else /* !CONFIG_FILE_LOCKING */
static inline int locks_mandatory_locked(struct file *file) static inline int locks_mandatory_locked(struct file *file)
{ {
...@@ -2092,6 +2103,11 @@ static inline int break_deleg_wait(struct inode **delegated_inode) ...@@ -2092,6 +2103,11 @@ static inline int break_deleg_wait(struct inode **delegated_inode)
return 0; return 0;
} }
static inline int break_layout(struct inode *inode, bool wait)
{
return 0;
}
#endif /* CONFIG_FILE_LOCKING */ #endif /* CONFIG_FILE_LOCKING */
/* fs/open.c */ /* fs/open.c */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment