File locking related changes for v3.18 (pile #1)

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJUNZK4AAoJEAAOaEEZVoIVI08P/iM7eaIVRnqaqtWw/JBzxiba
 EMDlJYUBSlv6lYk9s8RJT4bMmcmGAKSYzVAHSoPahzNcqTDdFLeDTLGxJ8uKBbjf
 d1qRRdH1yZHGUzCvJq3mEendjfXn435Y3YburUxjLfmzrzW7EbMvndiQsS5dhAm9
 PEZ+wrKF/zFL7LuXa1YznYrbqOD/GRsJAXGEWc3kNwfS9avephVG/RI3GtpI2PJj
 RY1mf8P7+WOlrShYoEuUo5aqs01MnU70LbqGHzY8/QKH+Cb0SOkCHZPZyClpiA+G
 MMJ+o2XWcif3BZYz+dobwz/FpNZ0Bar102xvm2E8fqByr/T20JFjzooTKsQ+PtCk
 DetQptrU2gtyZDKtInJUQSDPrs4cvA13TW+OEB1tT8rKBnmyEbY3/TxBpBTB9E6j
 eb/V3iuWnywR3iE+yyvx24Qe7Pov6deM31s46+Vj+GQDuWmAUJXemhfzPtZiYpMT
 exMXTyDS3j+W+kKqHblfU5f+Bh1eYGpG2m43wJVMLXKV7NwDf8nVV+Wea962ga+w
 BAM3ia4JRVgRWJBPsnre3lvGT5kKPyfTZsoG+kOfRxiorus2OABoK+SIZBZ+c65V
 Xh8VH5p3qyCUBOynXlHJWFqYWe2wH0LfbPrwe9dQwTwON51WF082EMG5zxTG0Ymf
 J2z9Shz68zu0ok8cuSlo
 =Hhee
 -----END PGP SIGNATURE-----

Merge tag 'locks-v3.18-1' of git://git.samba.org/jlayton/linux

Pull file locking related changes from Jeff Layton:
 "This release is a little more busy for file locking changes than the
  last:

   - a set of patches from Kinglong Mee to fix the lockowner handling in
     knfsd
   - a pile of cleanups to the internal file lease API.  This should get
     us a bit closer to allowing for setlease methods that can block.

  There are some dependencies between mine and Bruce's trees this cycle,
  and I based my tree on top of the requisite patches in Bruce's tree"

* tag 'locks-v3.18-1' of git://git.samba.org/jlayton/linux: (26 commits)
  locks: fix fcntl_setlease/getlease return when !CONFIG_FILE_LOCKING
  locks: flock_make_lock should return a struct file_lock (or PTR_ERR)
  locks: set fl_owner for leases to filp instead of current->files
  locks: give lm_break a return value
  locks: __break_lease cleanup in preparation of allowing direct removal of leases
  locks: remove i_have_this_lease check from __break_lease
  locks: move freeing of leases outside of i_lock
  locks: move i_lock acquisition into generic_*_lease handlers
  locks: define a lm_setup handler for leases
  locks: plumb a "priv" pointer into the setlease routines
  nfsd: don't keep a pointer to the lease in nfs4_file
  locks: clean up vfs_setlease kerneldoc comments
  locks: generic_delete_lease doesn't need a file_lock at all
  nfsd: fix potential lease memory leak in nfs4_setlease
  locks: close potential race in lease_get_mtime
  security: make security_file_set_fowner, f_setown and __f_setown void return
  locks: consolidate "nolease" routines
  locks: remove lock_may_read and lock_may_write
  lockd: rip out deferred lock handling from testlock codepath
  NFSD: Get reference of lockowner when coping file_lock
  ...
This commit is contained in:
Linus Torvalds 2014-10-11 13:21:34 -04:00
commit ef4a48c513
26 changed files with 354 additions and 488 deletions

View File

@ -464,15 +464,12 @@ prototypes:
size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,
size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
int (*setlease)(struct file *, long, struct file_lock **, void **);
long (*fallocate)(struct file *, int, loff_t, loff_t);
};
locking rules:
All may block except for ->setlease.
No VFS locks held on entry except for ->setlease.
->setlease has the file_list_lock held and must not sleep.
All may block.
->llseek() locking has moved from llseek to the individual llseek
implementations. If your fs is not using generic_file_llseek, you
@ -496,6 +493,10 @@ components. And there are other reasons why the current interface is a mess...
->read on directories probably must go away - we should just enforce -EISDIR
in sys_read() and friends.
->setlease operations should call generic_setlease() before or after setting
the lease within the individual filesystem to record the result of the
operation
--------------------------- dquot_operations -------------------------------
prototypes:
int (*write_dquot) (struct dquot *);

View File

@ -826,7 +826,7 @@ struct file_operations {
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long arg, struct file_lock **);
int (*setlease)(struct file *, long arg, struct file_lock **, void **);
long (*fallocate)(struct file *, int mode, loff_t offset, loff_t len);
int (*show_fdinfo)(struct seq_file *m, struct file *f);
};
@ -895,8 +895,9 @@ otherwise noted.
splice_read: called by the VFS to splice data from file to a pipe. This
method is used by the splice(2) system call
setlease: called by the VFS to set or release a file lock lease.
setlease has the file_lock_lock held and must not sleep.
setlease: called by the VFS to set or release a file lock lease. setlease
implementations should call generic_setlease to record or remove
the lease in the inode after setting it.
fallocate: called by the VFS to preallocate blocks or punch a hole.

View File

@ -2152,9 +2152,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on)
goto out;
if (on) {
ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0);
if (ret)
goto out;
__f_setown(file, task_pid(current), PIDTYPE_PID, 0);
tfile->flags |= TUN_FASYNC;
} else
tfile->flags &= ~TUN_FASYNC;

View File

@ -2186,8 +2186,9 @@ static int __tty_fasync(int fd, struct file *filp, int on)
}
get_pid(pid);
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
retval = __f_setown(filp, pid, type, 0);
__f_setown(filp, pid, type, 0);
put_pid(pid);
retval = 0;
}
out:
return retval;

View File

@ -813,7 +813,8 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
return generic_file_llseek(file, offset, whence);
}
static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
static int
cifs_setlease(struct file *file, long arg, struct file_lock **lease, void **priv)
{
/*
* Note that this is called by vfs setlease with i_lock held to
@ -829,7 +830,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
if (arg == F_UNLCK ||
((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode))))
return generic_setlease(file, arg, lease);
return generic_setlease(file, arg, lease, priv);
else if (tlink_tcon(cfile->tlink)->local_lease &&
!CIFS_CACHE_READ(CIFS_I(inode)))
/*
@ -840,7 +841,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
* knows that the file won't be changed on the server by anyone
* else.
*/
return generic_setlease(file, arg, lease);
return generic_setlease(file, arg, lease, priv);
else
return -EAGAIN;
}

View File

@ -30,7 +30,7 @@ struct plock_op {
struct plock_xop {
struct plock_op xop;
void *callback;
int (*callback)(struct file_lock *fl, int result);
void *fl;
void *file;
struct file_lock flc;
@ -190,7 +190,7 @@ static int dlm_plock_callback(struct plock_op *op)
struct file *file;
struct file_lock *fl;
struct file_lock *flc;
int (*notify)(void *, void *, int) = NULL;
int (*notify)(struct file_lock *fl, int result) = NULL;
struct plock_xop *xop = (struct plock_xop *)op;
int rv = 0;
@ -209,7 +209,7 @@ static int dlm_plock_callback(struct plock_op *op)
notify = xop->callback;
if (op->info.rv) {
notify(fl, NULL, op->info.rv);
notify(fl, op->info.rv);
goto out;
}
@ -228,7 +228,7 @@ static int dlm_plock_callback(struct plock_op *op)
(unsigned long long)op->info.number, file, fl);
}
rv = notify(fl, NULL, 0);
rv = notify(fl, 0);
if (rv) {
/* XXX: We need to cancel the fs lock here: */
log_print("dlm_plock_callback: lock granted after lock request "

View File

@ -98,26 +98,19 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
write_unlock_irq(&filp->f_owner.lock);
}
int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
void __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
int force)
{
int err;
err = security_file_set_fowner(filp);
if (err)
return err;
security_file_set_fowner(filp);
f_modown(filp, pid, type, force);
return 0;
}
EXPORT_SYMBOL(__f_setown);
int f_setown(struct file *filp, unsigned long arg, int force)
void f_setown(struct file *filp, unsigned long arg, int force)
{
enum pid_type type;
struct pid *pid;
int who = arg;
int result;
type = PIDTYPE_PID;
if (who < 0) {
type = PIDTYPE_PGID;
@ -125,9 +118,8 @@ int f_setown(struct file *filp, unsigned long arg, int force)
}
rcu_read_lock();
pid = find_vpid(who);
result = __f_setown(filp, pid, type, force);
__f_setown(filp, pid, type, force);
rcu_read_unlock();
return result;
}
EXPORT_SYMBOL(f_setown);
@ -181,7 +173,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg)
if (owner.pid && !pid)
ret = -ESRCH;
else
ret = __f_setown(filp, pid, type, 1);
__f_setown(filp, pid, type, 1);
rcu_read_unlock();
return ret;
@ -302,7 +294,8 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
force_successful_syscall_return();
break;
case F_SETOWN:
err = f_setown(filp, arg, 1);
f_setown(filp, arg, 1);
err = 0;
break;
case F_GETOWN_EX:
err = f_getown_ex(filp, arg);

View File

@ -913,26 +913,6 @@ out_uninit:
#ifdef CONFIG_GFS2_FS_LOCKING_DLM
/**
* gfs2_setlease - acquire/release a file lease
* @file: the file pointer
* @arg: lease type
* @fl: file lock
*
* We don't currently have a way to enforce a lease across the whole
* cluster; until we do, disable leases (by just returning -EINVAL),
* unless the administrator has requested purely local locking.
*
* Locking: called under i_lock
*
* Returns: errno
*/
static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl)
{
return -EINVAL;
}
/**
* gfs2_lock - acquire/release a posix lock on a file
* @file: the file pointer
@ -1078,7 +1058,7 @@ const struct file_operations gfs2_file_fops = {
.flock = gfs2_flock,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.setlease = gfs2_setlease,
.setlease = simple_nosetlease,
.fallocate = gfs2_fallocate,
};

View File

@ -1075,3 +1075,21 @@ struct inode *alloc_anon_inode(struct super_block *s)
return inode;
}
EXPORT_SYMBOL(alloc_anon_inode);
/**
* simple_nosetlease - generic helper for prohibiting leases
* @filp: file pointer
* @arg: type of lease to obtain
* @flp: new lease supplied for insertion
* @priv: private data for lm_setup operation
*
* Generic helper for filesystems that do not wish to allow leases to be set.
* All arguments are ignored and it just returns -EINVAL.
*/
int
simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
void **priv)
{
return -EINVAL;
}
EXPORT_SYMBOL(simple_nosetlease);

View File

@ -245,7 +245,6 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host,
block->b_daemon = rqstp->rq_server;
block->b_host = host;
block->b_file = file;
block->b_fl = NULL;
file->f_count++;
/* Add to file's list of blocks */
@ -295,7 +294,6 @@ static void nlmsvc_free_block(struct kref *kref)
nlmsvc_freegrantargs(block->b_call);
nlmsvc_release_call(block->b_call);
nlm_release_file(block->b_file);
kfree(block->b_fl);
kfree(block);
}
@ -508,7 +506,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_host *host, struct nlm_lock *lock,
struct nlm_lock *conflock, struct nlm_cookie *cookie)
{
struct nlm_block *block = NULL;
int error;
__be32 ret;
@ -519,63 +516,26 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
/* Get existing block (in case client is busy-waiting) */
block = nlmsvc_lookup_block(file, lock);
if (block == NULL) {
struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
if (conf == NULL)
return nlm_granted;
block = nlmsvc_create_block(rqstp, host, file, lock, cookie);
if (block == NULL) {
kfree(conf);
return nlm_granted;
}
block->b_fl = conf;
}
if (block->b_flags & B_QUEUED) {
dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n",
block, block->b_flags, block->b_fl);
if (block->b_flags & B_TIMED_OUT) {
nlmsvc_unlink_block(block);
ret = nlm_lck_denied;
goto out;
}
if (block->b_flags & B_GOT_CALLBACK) {
nlmsvc_unlink_block(block);
if (block->b_fl != NULL
&& block->b_fl->fl_type != F_UNLCK) {
lock->fl = *block->b_fl;
goto conf_lock;
} else {
ret = nlm_granted;
goto out;
}
}
ret = nlm_drop_reply;
goto out;
}
if (locks_in_grace(SVC_NET(rqstp))) {
ret = nlm_lck_denied_grace_period;
goto out;
}
error = vfs_test_lock(file->f_file, &lock->fl);
if (error == FILE_LOCK_DEFERRED) {
ret = nlmsvc_defer_lock_rqst(rqstp, block);
goto out;
}
if (error) {
/* We can't currently deal with deferred test requests */
if (error == FILE_LOCK_DEFERRED)
WARN_ON_ONCE(1);
ret = nlm_lck_denied_nolocks;
goto out;
}
if (lock->fl.fl_type == F_UNLCK) {
ret = nlm_granted;
goto out;
}
conf_lock:
dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
lock->fl.fl_type, (long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
@ -586,10 +546,9 @@ conf_lock:
conflock->fl.fl_type = lock->fl.fl_type;
conflock->fl.fl_start = lock->fl.fl_start;
conflock->fl.fl_end = lock->fl.fl_end;
locks_release_private(&lock->fl);
ret = nlm_lck_denied;
out:
if (block)
nlmsvc_release_block(block);
return ret;
}
@ -660,29 +619,22 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l
* This is a callback from the filesystem for VFS file lock requests.
* It will be used if lm_grant is defined and the filesystem can not
* respond to the request immediately.
* For GETLK request it will copy the reply to the nlm_block.
* For SETLK or SETLKW request it will get the local posix lock.
* In all cases it will move the block to the head of nlm_blocked q where
* nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
* deferred rpc for GETLK and SETLK.
*/
static void
nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
int result)
nlmsvc_update_deferred_block(struct nlm_block *block, int result)
{
block->b_flags |= B_GOT_CALLBACK;
if (result == 0)
block->b_granted = 1;
else
block->b_flags |= B_TIMED_OUT;
if (conf) {
if (block->b_fl)
__locks_copy_lock(block->b_fl, conf);
}
}
static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
int result)
static int nlmsvc_grant_deferred(struct file_lock *fl, int result)
{
struct nlm_block *block;
int rc = -ENOENT;
@ -697,7 +649,7 @@ static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
rc = -ENOLCK;
break;
}
nlmsvc_update_deferred_block(block, conf, result);
nlmsvc_update_deferred_block(block, result);
} else if (result == 0)
block->b_granted = 1;

View File

@ -230,8 +230,12 @@ void locks_release_private(struct file_lock *fl)
fl->fl_ops->fl_release_private(fl);
fl->fl_ops = NULL;
}
fl->fl_lmops = NULL;
if (fl->fl_lmops) {
if (fl->fl_lmops->lm_put_owner)
fl->fl_lmops->lm_put_owner(fl);
fl->fl_lmops = NULL;
}
}
EXPORT_SYMBOL_GPL(locks_release_private);
@ -267,21 +271,10 @@ void locks_init_lock(struct file_lock *fl)
EXPORT_SYMBOL(locks_init_lock);
static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
{
if (fl->fl_ops) {
if (fl->fl_ops->fl_copy_lock)
fl->fl_ops->fl_copy_lock(new, fl);
new->fl_ops = fl->fl_ops;
}
if (fl->fl_lmops)
new->fl_lmops = fl->fl_lmops;
}
/*
* Initialize a new lock from an existing file_lock structure.
*/
void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
void locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
{
new->fl_owner = fl->fl_owner;
new->fl_pid = fl->fl_pid;
@ -290,22 +283,30 @@ void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
new->fl_type = fl->fl_type;
new->fl_start = fl->fl_start;
new->fl_end = fl->fl_end;
new->fl_lmops = fl->fl_lmops;
new->fl_ops = NULL;
new->fl_lmops = NULL;
if (fl->fl_lmops) {
if (fl->fl_lmops->lm_get_owner)
fl->fl_lmops->lm_get_owner(new, fl);
}
}
EXPORT_SYMBOL(__locks_copy_lock);
EXPORT_SYMBOL(locks_copy_conflock);
void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
{
/* "new" must be a freshly-initialized lock */
WARN_ON_ONCE(new->fl_ops);
__locks_copy_lock(new, fl);
locks_copy_conflock(new, fl);
new->fl_file = fl->fl_file;
new->fl_ops = fl->fl_ops;
new->fl_lmops = fl->fl_lmops;
locks_copy_private(new, fl);
if (fl->fl_ops) {
if (fl->fl_ops->fl_copy_lock)
fl->fl_ops->fl_copy_lock(new, fl);
}
}
EXPORT_SYMBOL(locks_copy_lock);
@ -325,17 +326,18 @@ static inline int flock_translate_cmd(int cmd) {
}
/* Fill in a file_lock structure with an appropriate FLOCK lock. */
static int flock_make_lock(struct file *filp, struct file_lock **lock,
unsigned int cmd)
static struct file_lock *
flock_make_lock(struct file *filp, unsigned int cmd)
{
struct file_lock *fl;
int type = flock_translate_cmd(cmd);
if (type < 0)
return type;
return ERR_PTR(type);
fl = locks_alloc_lock();
if (fl == NULL)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
fl->fl_file = filp;
fl->fl_owner = filp;
@ -344,8 +346,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock,
fl->fl_type = type;
fl->fl_end = OFFSET_MAX;
*lock = fl;
return 0;
return fl;
}
static int assign_type(struct file_lock *fl, long type)
@ -426,14 +427,34 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
}
/* default lease lock manager operations */
static void lease_break_callback(struct file_lock *fl)
static bool
lease_break_callback(struct file_lock *fl)
{
kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
return false;
}
static void
lease_setup(struct file_lock *fl, void **priv)
{
struct file *filp = fl->fl_file;
struct fasync_struct *fa = *priv;
/*
* fasync_insert_entry() returns the old entry if any. If there was no
* old entry, then it used "priv" and inserted it into the fasync list.
* Clear the pointer to indicate that it shouldn't be freed.
*/
if (!fasync_insert_entry(fa->fa_fd, filp, &fl->fl_fasync, fa))
*priv = NULL;
__f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
}
static const struct lock_manager_operations lease_manager_ops = {
.lm_break = lease_break_callback,
.lm_change = lease_modify,
.lm_setup = lease_setup,
};
/*
@ -444,7 +465,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl)
if (assign_type(fl, type) != 0)
return -EINVAL;
fl->fl_owner = current->files;
fl->fl_owner = filp;
fl->fl_pid = current->tgid;
fl->fl_file = filp;
@ -735,7 +756,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
break;
}
if (cfl) {
__locks_copy_lock(fl, cfl);
locks_copy_conflock(fl, cfl);
if (cfl->fl_nspid)
fl->fl_pid = pid_vnr(cfl->fl_nspid);
} else
@ -941,7 +962,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
if (!posix_locks_conflict(request, fl))
continue;
if (conflock)
__locks_copy_lock(conflock, fl);
locks_copy_conflock(conflock, fl);
error = -EAGAIN;
if (!(request->fl_flags & FL_SLEEP))
goto out;
@ -1273,7 +1294,7 @@ static void lease_clear_pending(struct file_lock *fl, int arg)
}
/* We already had a lease on this file; just change its type */
int lease_modify(struct file_lock **before, int arg)
int lease_modify(struct file_lock **before, int arg, struct list_head *dispose)
{
struct file_lock *fl = *before;
int error = assign_type(fl, arg);
@ -1292,11 +1313,10 @@ int lease_modify(struct file_lock **before, int arg)
printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
fl->fl_fasync = NULL;
}
locks_delete_lock(before, NULL);
locks_delete_lock(before, dispose);
}
return 0;
}
EXPORT_SYMBOL(lease_modify);
static bool past_time(unsigned long then)
@ -1307,18 +1327,20 @@ static bool past_time(unsigned long then)
return time_after(jiffies, then);
}
static void time_out_leases(struct inode *inode)
static void time_out_leases(struct inode *inode, struct list_head *dispose)
{
struct file_lock **before;
struct file_lock *fl;
lockdep_assert_held(&inode->i_lock);
before = &inode->i_flock;
while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) {
trace_time_out_leases(inode, fl);
if (past_time(fl->fl_downgrade_time))
lease_modify(before, F_RDLCK);
lease_modify(before, F_RDLCK, dispose);
if (past_time(fl->fl_break_time))
lease_modify(before, F_UNLCK);
lease_modify(before, F_UNLCK, dispose);
if (fl == *before) /* lease_modify may have freed fl */
before = &fl->fl_next;
}
@ -1331,6 +1353,20 @@ static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
return locks_conflict(breaker, lease);
}
static bool
any_leases_conflict(struct inode *inode, struct file_lock *breaker)
{
struct file_lock *fl;
lockdep_assert_held(&inode->i_lock);
for (fl = inode->i_flock ; fl && IS_LEASE(fl); fl = fl->fl_next) {
if (leases_conflict(fl, breaker))
return true;
}
return false;
}
/**
* __break_lease - revoke all outstanding leases on file
* @inode: the inode of the file to return
@ -1347,12 +1383,11 @@ static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
{
int error = 0;
struct file_lock *new_fl, *flock;
struct file_lock *fl;
struct file_lock *new_fl;
struct file_lock *fl, **before;
unsigned long break_time;
int i_have_this_lease = 0;
bool lease_conflict = false;
int want_write = (mode & O_ACCMODE) != O_RDONLY;
LIST_HEAD(dispose);
new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK);
if (IS_ERR(new_fl))
@ -1361,20 +1396,9 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
spin_lock(&inode->i_lock);
time_out_leases(inode);
time_out_leases(inode, &dispose);
flock = inode->i_flock;
if ((flock == NULL) || !IS_LEASE(flock))
goto out;
for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
if (leases_conflict(fl, new_fl)) {
lease_conflict = true;
if (fl->fl_owner == current->files)
i_have_this_lease = 1;
}
}
if (!lease_conflict)
if (!any_leases_conflict(inode, new_fl))
goto out;
break_time = 0;
@ -1384,7 +1408,9 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
break_time++; /* so that 0 means no break time */
}
for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
for (before = &inode->i_flock;
((fl = *before) != NULL) && IS_LEASE(fl);
before = &fl->fl_next) {
if (!leases_conflict(fl, new_fl))
continue;
if (want_write) {
@ -1393,51 +1419,56 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
fl->fl_flags |= FL_UNLOCK_PENDING;
fl->fl_break_time = break_time;
} else {
if (lease_breaking(flock))
if (lease_breaking(inode->i_flock))
continue;
fl->fl_flags |= FL_DOWNGRADE_PENDING;
fl->fl_downgrade_time = break_time;
}
fl->fl_lmops->lm_break(fl);
if (fl->fl_lmops->lm_break(fl))
locks_delete_lock(before, &dispose);
}
if (i_have_this_lease || (mode & O_NONBLOCK)) {
fl = inode->i_flock;
if (!fl || !IS_LEASE(fl))
goto out;
if (mode & O_NONBLOCK) {
trace_break_lease_noblock(inode, new_fl);
error = -EWOULDBLOCK;
goto out;
}
restart:
break_time = flock->fl_break_time;
break_time = inode->i_flock->fl_break_time;
if (break_time != 0)
break_time -= jiffies;
if (break_time == 0)
break_time++;
locks_insert_block(flock, new_fl);
locks_insert_block(inode->i_flock, new_fl);
trace_break_lease_block(inode, new_fl);
spin_unlock(&inode->i_lock);
locks_dispose_list(&dispose);
error = wait_event_interruptible_timeout(new_fl->fl_wait,
!new_fl->fl_next, break_time);
spin_lock(&inode->i_lock);
trace_break_lease_unblock(inode, new_fl);
locks_delete_block(new_fl);
if (error >= 0) {
if (error == 0)
time_out_leases(inode);
/*
* Wait for the next conflicting lease that has not been
* broken yet
*/
for (flock = inode->i_flock; flock && IS_LEASE(flock);
flock = flock->fl_next) {
if (leases_conflict(new_fl, flock))
if (error == 0)
time_out_leases(inode, &dispose);
if (any_leases_conflict(inode, new_fl))
goto restart;
}
error = 0;
}
out:
spin_unlock(&inode->i_lock);
locks_dispose_list(&dispose);
locks_free_lock(new_fl);
return error;
}
@ -1455,8 +1486,18 @@ EXPORT_SYMBOL(__break_lease);
*/
void lease_get_mtime(struct inode *inode, struct timespec *time)
{
struct file_lock *flock = inode->i_flock;
bool has_lease = false;
struct file_lock *flock;
if (inode->i_flock) {
spin_lock(&inode->i_lock);
flock = inode->i_flock;
if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK))
has_lease = true;
spin_unlock(&inode->i_lock);
}
if (has_lease)
*time = current_fs_time(inode->i_sb);
else
*time = inode->i_mtime;
@ -1492,9 +1533,10 @@ int fcntl_getlease(struct file *filp)
struct file_lock *fl;
struct inode *inode = file_inode(filp);
int type = F_UNLCK;
LIST_HEAD(dispose);
spin_lock(&inode->i_lock);
time_out_leases(file_inode(filp));
time_out_leases(file_inode(filp), &dispose);
for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl);
fl = fl->fl_next) {
if (fl->fl_file == filp) {
@ -1503,6 +1545,7 @@ int fcntl_getlease(struct file *filp)
}
}
spin_unlock(&inode->i_lock);
locks_dispose_list(&dispose);
return type;
}
@ -1532,13 +1575,15 @@ check_conflicting_open(const struct dentry *dentry, const long arg)
return ret;
}
static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
static int
generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv)
{
struct file_lock *fl, **before, **my_before = NULL, *lease;
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
bool is_deleg = (*flp)->fl_flags & FL_DELEG;
int error;
LIST_HEAD(dispose);
lease = *flp;
trace_generic_add_lease(inode, lease);
@ -1561,6 +1606,8 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
return -EINVAL;
}
spin_lock(&inode->i_lock);
time_out_leases(inode, &dispose);
error = check_conflicting_open(dentry, arg);
if (error)
goto out;
@ -1596,10 +1643,11 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
}
if (my_before != NULL) {
error = lease->fl_lmops->lm_change(my_before, arg);
if (!error)
*flp = *my_before;
lease = *my_before;
error = lease->fl_lmops->lm_change(my_before, arg, &dispose);
if (error)
goto out;
goto out_setup;
}
error = -EINVAL;
@ -1619,29 +1667,46 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
smp_mb();
error = check_conflicting_open(dentry, arg);
if (error)
locks_unlink_lock(before);
goto out_unlink;
out_setup:
if (lease->fl_lmops->lm_setup)
lease->fl_lmops->lm_setup(lease, priv);
out:
spin_unlock(&inode->i_lock);
locks_dispose_list(&dispose);
if (is_deleg)
mutex_unlock(&inode->i_mutex);
if (!error && !my_before)
*flp = NULL;
return error;
out_unlink:
locks_unlink_lock(before);
goto out;
}
static int generic_delete_lease(struct file *filp, struct file_lock **flp)
static int generic_delete_lease(struct file *filp)
{
int error = -EAGAIN;
struct file_lock *fl, **before;
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
LIST_HEAD(dispose);
trace_generic_delete_lease(inode, *flp);
spin_lock(&inode->i_lock);
time_out_leases(inode, &dispose);
for (before = &inode->i_flock;
((fl = *before) != NULL) && IS_LEASE(fl);
before = &fl->fl_next) {
if (fl->fl_file != filp)
continue;
return (*flp)->fl_lmops->lm_change(before, F_UNLCK);
if (fl->fl_file == filp)
break;
}
return -EAGAIN;
trace_generic_delete_lease(inode, fl);
if (fl)
error = fl->fl_lmops->lm_change(before, F_UNLCK, &dispose);
spin_unlock(&inode->i_lock);
locks_dispose_list(&dispose);
return error;
}
/**
@ -1649,13 +1714,14 @@ static int generic_delete_lease(struct file *filp, struct file_lock **flp)
* @filp: file pointer
* @arg: type of lease to obtain
* @flp: input - file_lock to use, output - file_lock inserted
* @priv: private data for lm_setup (may be NULL if lm_setup
* doesn't require it)
*
* The (input) flp->fl_lmops->lm_break function is required
* by break_lease().
*
* Called with inode->i_lock held.
*/
int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
void **priv)
{
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
@ -1669,83 +1735,52 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
if (error)
return error;
time_out_leases(inode);
BUG_ON(!(*flp)->fl_lmops->lm_break);
switch (arg) {
case F_UNLCK:
return generic_delete_lease(filp, flp);
return generic_delete_lease(filp);
case F_RDLCK:
case F_WRLCK:
return generic_add_lease(filp, arg, flp);
if (!(*flp)->fl_lmops->lm_break) {
WARN_ON_ONCE(1);
return -ENOLCK;
}
return generic_add_lease(filp, arg, flp, priv);
default:
return -EINVAL;
}
}
EXPORT_SYMBOL(generic_setlease);
static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
{
if (filp->f_op->setlease)
return filp->f_op->setlease(filp, arg, lease);
else
return generic_setlease(filp, arg, lease);
}
/**
* vfs_setlease - sets a lease on an open file
* @filp: file pointer
* @arg: type of lease to obtain
* @lease: file_lock to use
* @lease: file_lock to use when adding a lease
* @priv: private info for lm_setup when adding a lease (may be
* NULL if lm_setup doesn't require it)
*
* Call this to establish a lease on the file.
* The (*lease)->fl_lmops->lm_break operation must be set; if not,
* break_lease will oops!
* Call this to establish a lease on the file. The "lease" argument is not
* used for F_UNLCK requests and may be NULL. For commands that set or alter
* an existing lease, the (*lease)->fl_lmops->lm_break operation must be set;
* if not, this function will return -ENOLCK (and generate a scary-looking
* stack trace).
*
* This will call the filesystem's setlease file method, if
* defined. Note that there is no getlease method; instead, the
* filesystem setlease method should call back to setlease() to
* add a lease to the inode's lease list, where fcntl_getlease() can
* find it. Since fcntl_getlease() only reports whether the current
* task holds a lease, a cluster filesystem need only do this for
* leases held by processes on this node.
*
* There is also no break_lease method; filesystems that
* handle their own leases should break leases themselves from the
* filesystem's open, create, and (on truncate) setattr methods.
*
* Warning: the only current setlease methods exist only to disable
* leases in certain cases. More vfs changes may be required to
* allow a full filesystem lease implementation.
* The "priv" pointer is passed directly to the lm_setup function as-is. It
* may be NULL if the lm_setup operation doesn't require it.
*/
int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
int
vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
{
struct inode *inode = file_inode(filp);
int error;
spin_lock(&inode->i_lock);
error = __vfs_setlease(filp, arg, lease);
spin_unlock(&inode->i_lock);
return error;
if (filp->f_op->setlease)
return filp->f_op->setlease(filp, arg, lease, priv);
else
return generic_setlease(filp, arg, lease, priv);
}
EXPORT_SYMBOL_GPL(vfs_setlease);
static int do_fcntl_delete_lease(struct file *filp)
{
struct file_lock fl, *flp = &fl;
lease_init(filp, F_UNLCK, flp);
return vfs_setlease(filp, F_UNLCK, &flp);
}
static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
{
struct file_lock *fl, *ret;
struct inode *inode = file_inode(filp);
struct file_lock *fl;
struct fasync_struct *new;
int error;
@ -1758,26 +1793,9 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
locks_free_lock(fl);
return -ENOMEM;
}
ret = fl;
spin_lock(&inode->i_lock);
error = __vfs_setlease(filp, arg, &ret);
if (error)
goto out_unlock;
if (ret == fl)
fl = NULL;
new->fa_fd = fd;
/*
* fasync_insert_entry() returns the old entry if any.
* If there was no old entry, then it used 'new' and
* inserted it into the fasync list. Clear new so that
* we don't release it here.
*/
if (!fasync_insert_entry(fd, filp, &ret->fl_fasync, new))
new = NULL;
error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
out_unlock:
spin_unlock(&inode->i_lock);
error = vfs_setlease(filp, arg, &fl, (void **)&new);
if (fl)
locks_free_lock(fl);
if (new)
@ -1798,7 +1816,7 @@ out_unlock:
int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{
if (arg == F_UNLCK)
return do_fcntl_delete_lease(filp);
return vfs_setlease(filp, F_UNLCK, NULL, NULL);
return do_fcntl_add_lease(fd, filp, arg);
}
@ -1867,9 +1885,12 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
!(f.file->f_mode & (FMODE_READ|FMODE_WRITE)))
goto out_putf;
error = flock_make_lock(f.file, &lock, cmd);
if (error)
lock = flock_make_lock(f.file, cmd);
if (IS_ERR(lock)) {
error = PTR_ERR(lock);
goto out_putf;
}
if (can_sleep)
lock->fl_flags |= FL_SLEEP;
@ -1981,11 +2002,13 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l)
if (file_lock.fl_type != F_UNLCK) {
error = posix_lock_to_flock(&flock, &file_lock);
if (error)
goto out;
goto rel_priv;
}
error = -EFAULT;
if (!copy_to_user(l, &flock, sizeof(flock)))
error = 0;
rel_priv:
locks_release_private(&file_lock);
out:
return error;
}
@ -2207,6 +2230,7 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
if (!copy_to_user(l, &flock, sizeof(flock)))
error = 0;
locks_release_private(&file_lock);
out:
return error;
}
@ -2369,7 +2393,7 @@ void locks_remove_file(struct file *filp)
while ((fl = *before) != NULL) {
if (fl->fl_file == filp) {
if (IS_LEASE(fl)) {
lease_modify(before, F_UNLCK);
lease_modify(before, F_UNLCK, &dispose);
continue;
}
@ -2593,86 +2617,6 @@ static int __init proc_locks_init(void)
module_init(proc_locks_init);
#endif
/**
* lock_may_read - checks that the region is free of locks
* @inode: the inode that is being read
* @start: the first byte to read
* @len: the number of bytes to read
*
* Emulates Windows locking requirements. Whole-file
* mandatory locks (share modes) can prohibit a read and
* byte-range POSIX locks can prohibit a read if they overlap.
*
* N.B. this function is only ever called
* from knfsd and ownership of locks is never checked.
*/
int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
{
struct file_lock *fl;
int result = 1;
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (IS_POSIX(fl)) {
if (fl->fl_type == F_RDLCK)
continue;
if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
continue;
} else if (IS_FLOCK(fl)) {
if (!(fl->fl_type & LOCK_MAND))
continue;
if (fl->fl_type & LOCK_READ)
continue;
} else
continue;
result = 0;
break;
}
spin_unlock(&inode->i_lock);
return result;
}
EXPORT_SYMBOL(lock_may_read);
/**
* lock_may_write - checks that the region is free of locks
* @inode: the inode that is being written
* @start: the first byte to write
* @len: the number of bytes to write
*
* Emulates Windows locking requirements. Whole-file
* mandatory locks (share modes) can prohibit a write and
* byte-range POSIX locks can prohibit a write if they overlap.
*
* N.B. this function is only ever called
* from knfsd and ownership of locks is never checked.
*/
int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
{
struct file_lock *fl;
int result = 1;
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (IS_POSIX(fl)) {
if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
continue;
} else if (IS_FLOCK(fl)) {
if (!(fl->fl_type & LOCK_MAND))
continue;
if (fl->fl_type & LOCK_WRITE)
continue;
} else
continue;
result = 0;
break;
}
spin_unlock(&inode->i_lock);
return result;
}
EXPORT_SYMBOL(lock_may_write);
static int __init filelock_init(void)
{
int i;

View File

@ -919,17 +919,6 @@ int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
}
EXPORT_SYMBOL_GPL(nfs_flock);
/*
* There is no protocol support for leases, so we have no way to implement
* them correctly in the face of opens by other clients.
*/
int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
{
dprintk("NFS: setlease(%pD2, arg=%ld)\n", file, arg);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(nfs_setlease);
const struct file_operations nfs_file_operations = {
.llseek = nfs_file_llseek,
.read = new_sync_read,
@ -946,6 +935,6 @@ const struct file_operations nfs_file_operations = {
.splice_read = nfs_file_splice_read,
.splice_write = iter_file_splice_write,
.check_flags = nfs_check_flags,
.setlease = nfs_setlease,
.setlease = simple_nosetlease,
};
EXPORT_SYMBOL_GPL(nfs_file_operations);

View File

@ -339,7 +339,6 @@ int nfs_file_release(struct inode *, struct file *);
int nfs_lock(struct file *, int, struct file_lock *);
int nfs_flock(struct file *, int, struct file_lock *);
int nfs_check_flags(int);
int nfs_setlease(struct file *, long, struct file_lock **);
/* inode.c */
extern struct workqueue_struct *nfsiod_workqueue;

View File

@ -131,5 +131,5 @@ const struct file_operations nfs4_file_operations = {
.splice_read = nfs_file_splice_read,
.splice_write = iter_file_splice_write,
.check_flags = nfs_check_flags,
.setlease = nfs_setlease,
.setlease = simple_nosetlease,
};

View File

@ -218,6 +218,13 @@ static void nfsd4_put_session(struct nfsd4_session *ses)
spin_unlock(&nn->client_lock);
}
static inline struct nfs4_stateowner *
nfs4_get_stateowner(struct nfs4_stateowner *sop)
{
atomic_inc(&sop->so_count);
return sop;
}
static int
same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner)
{
@ -237,10 +244,8 @@ find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
so_strhash) {
if (!so->so_is_open_owner)
continue;
if (same_owner_str(so, &open->op_owner)) {
atomic_inc(&so->so_count);
return openowner(so);
}
if (same_owner_str(so, &open->op_owner))
return openowner(nfs4_get_stateowner(so));
}
return NULL;
}
@ -678,18 +683,14 @@ nfs4_put_stid(struct nfs4_stid *s)
static void nfs4_put_deleg_lease(struct nfs4_file *fp)
{
struct file *filp = NULL;
struct file_lock *fl;
spin_lock(&fp->fi_lock);
if (fp->fi_lease && atomic_dec_and_test(&fp->fi_delegees)) {
if (fp->fi_deleg_file && atomic_dec_and_test(&fp->fi_delegees))
swap(filp, fp->fi_deleg_file);
fl = fp->fi_lease;
fp->fi_lease = NULL;
}
spin_unlock(&fp->fi_lock);
if (filp) {
vfs_setlease(filp, F_UNLCK, &fl);
vfs_setlease(filp, F_UNLCK, NULL, NULL);
fput(filp);
}
}
@ -1655,7 +1656,7 @@ __destroy_client(struct nfs4_client *clp)
}
while (!list_empty(&clp->cl_openowners)) {
oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
atomic_inc(&oo->oo_owner.so_count);
nfs4_get_stateowner(&oo->oo_owner);
release_openowner(oo);
}
nfsd4_shutdown_callback(clp);
@ -3067,8 +3068,8 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh)
INIT_LIST_HEAD(&fp->fi_stateids);
INIT_LIST_HEAD(&fp->fi_delegations);
fh_copy_shallow(&fp->fi_fhandle, fh);
fp->fi_deleg_file = NULL;
fp->fi_had_conflict = false;
fp->fi_lease = NULL;
fp->fi_share_deny = 0;
memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
memset(fp->fi_access, 0, sizeof(fp->fi_access));
@ -3136,8 +3137,7 @@ static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate,
{
if (!nfsd4_has_session(cstate)) {
mutex_lock(&so->so_replay.rp_mutex);
cstate->replay_owner = so;
atomic_inc(&so->so_count);
cstate->replay_owner = nfs4_get_stateowner(so);
}
}
@ -3236,8 +3236,7 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
atomic_inc(&stp->st_stid.sc_count);
stp->st_stid.sc_type = NFS4_OPEN_STID;
INIT_LIST_HEAD(&stp->st_locks);
stp->st_stateowner = &oo->oo_owner;
atomic_inc(&stp->st_stateowner->so_count);
stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner);
get_nfs4_file(fp);
stp->st_stid.sc_file = fp;
stp->st_access_bmap = 0;
@ -3434,18 +3433,20 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
}
/* Called from break_lease() with i_lock held. */
static void nfsd_break_deleg_cb(struct file_lock *fl)
static bool
nfsd_break_deleg_cb(struct file_lock *fl)
{
bool ret = false;
struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
struct nfs4_delegation *dp;
if (!fp) {
WARN(1, "(%p)->fl_owner NULL\n", fl);
return;
return ret;
}
if (fp->fi_had_conflict) {
WARN(1, "duplicate break on %p\n", fp);
return;
return ret;
}
/*
* We don't want the locks code to timeout the lease for us;
@ -3457,24 +3458,23 @@ static void nfsd_break_deleg_cb(struct file_lock *fl)
spin_lock(&fp->fi_lock);
fp->fi_had_conflict = true;
/*
* If there are no delegations on the list, then we can't count on this
* lease ever being cleaned up. Set the fl_break_time to jiffies so that
* time_out_leases will do it ASAP. The fact that fi_had_conflict is now
* true should keep any new delegations from being hashed.
* If there are no delegations on the list, then return true
* so that the lease code will go ahead and delete it.
*/
if (list_empty(&fp->fi_delegations))
fl->fl_break_time = jiffies;
ret = true;
else
list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
nfsd_break_one_deleg(dp);
spin_unlock(&fp->fi_lock);
return ret;
}
static
int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
static int
nfsd_change_deleg_cb(struct file_lock **onlist, int arg, struct list_head *dispose)
{
if (arg & F_UNLCK)
return lease_modify(onlist, arg);
return lease_modify(onlist, arg, dispose);
else
return -EAGAIN;
}
@ -3820,7 +3820,7 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
static int nfs4_setlease(struct nfs4_delegation *dp)
{
struct nfs4_file *fp = dp->dl_stid.sc_file;
struct file_lock *fl;
struct file_lock *fl, *ret;
struct file *filp;
int status = 0;
@ -3834,11 +3834,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
return -EBADF;
}
fl->fl_file = filp;
status = vfs_setlease(filp, fl->fl_type, &fl);
if (status) {
ret = fl;
status = vfs_setlease(filp, fl->fl_type, &fl, NULL);
if (fl)
locks_free_lock(fl);
if (status)
goto out_fput;
}
spin_lock(&state_lock);
spin_lock(&fp->fi_lock);
/* Did the lease get broken before we took the lock? */
@ -3846,13 +3847,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
if (fp->fi_had_conflict)
goto out_unlock;
/* Race breaker */
if (fp->fi_lease) {
if (fp->fi_deleg_file) {
status = 0;
atomic_inc(&fp->fi_delegees);
hash_delegation_locked(dp, fp);
goto out_unlock;
}
fp->fi_lease = fl;
fp->fi_deleg_file = filp;
atomic_set(&fp->fi_delegees, 1);
hash_delegation_locked(dp, fp);
@ -3885,7 +3885,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
spin_lock(&state_lock);
spin_lock(&fp->fi_lock);
dp->dl_stid.sc_file = fp;
if (!fp->fi_lease) {
if (!fp->fi_deleg_file) {
spin_unlock(&fp->fi_lock);
spin_unlock(&state_lock);
status = nfs4_setlease(dp);
@ -4929,9 +4929,25 @@ nfs4_transform_lock_offset(struct file_lock *lock)
lock->fl_end = OFFSET_MAX;
}
/* Hack!: For now, we're defining this just so we can use a pointer to it
* as a unique cookie to identify our (NFSv4's) posix locks. */
static void nfsd4_fl_get_owner(struct file_lock *dst, struct file_lock *src)
{
struct nfs4_lockowner *lo = (struct nfs4_lockowner *)src->fl_owner;
dst->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lo->lo_owner));
}
static void nfsd4_fl_put_owner(struct file_lock *fl)
{
struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner;
if (lo) {
nfs4_put_stateowner(&lo->lo_owner);
fl->fl_owner = NULL;
}
}
static const struct lock_manager_operations nfsd_posix_mng_ops = {
.lm_get_owner = nfsd4_fl_get_owner,
.lm_put_owner = nfsd4_fl_put_owner,
};
static inline void
@ -4977,10 +4993,8 @@ find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner,
so_strhash) {
if (so->so_is_open_owner)
continue;
if (!same_owner_str(so, owner))
continue;
atomic_inc(&so->so_count);
return lockowner(so);
if (same_owner_str(so, owner))
return lockowner(nfs4_get_stateowner(so));
}
return NULL;
}
@ -5059,8 +5073,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
atomic_inc(&stp->st_stid.sc_count);
stp->st_stid.sc_type = NFS4_LOCK_STID;
stp->st_stateowner = &lo->lo_owner;
atomic_inc(&lo->lo_owner.so_count);
stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
get_nfs4_file(fp);
stp->st_stid.sc_file = fp;
stp->st_stid.sc_free = nfs4_free_lock_stateid;
@ -5299,7 +5312,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_openmode;
goto out;
}
file_lock->fl_owner = (fl_owner_t)lock_sop;
file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
file_lock->fl_pid = current->tgid;
file_lock->fl_file = filp;
file_lock->fl_flags = FL_POSIX;
@ -5495,7 +5509,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
}
file_lock->fl_type = F_UNLCK;
file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
file_lock->fl_pid = current->tgid;
file_lock->fl_file = filp;
file_lock->fl_flags = FL_POSIX;
@ -5602,7 +5616,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
}
}
atomic_inc(&sop->so_count);
nfs4_get_stateowner(sop);
break;
}
spin_unlock(&clp->cl_lock);

View File

@ -486,7 +486,6 @@ struct nfs4_file {
atomic_t fi_access[2];
u32 fi_share_deny;
struct file *fi_deleg_file;
struct file_lock *fi_lease;
atomic_t fi_delegees;
struct knfsd_fh fi_fhandle;
bool fi_had_conflict;

View File

@ -346,13 +346,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
goto out;
}
error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
if (error) {
/* if we added, we must shoot */
if (dn_mark == new_dn_mark)
destroy = 1;
goto out;
}
__f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
error = attach_dn(dn, dn_mark, id, fd, filp, mask);
/* !error means that we attached the dn to the dn_mark, so don't free it */

View File

@ -851,13 +851,7 @@ static inline struct file *get_file(struct file *f)
*/
#define FILE_LOCK_DEFERRED 1
/*
* The POSIX file lock owner is determined by
* the "struct files_struct" in the thread group
* (or NULL for no owner - BSD locks).
*
* Lockd stuffs a "host" pointer into this.
*/
/* legacy typedef, should eventually be removed */
typedef void *fl_owner_t;
struct file_lock_operations {
@ -868,10 +862,13 @@ struct file_lock_operations {
struct lock_manager_operations {
int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
unsigned long (*lm_owner_key)(struct file_lock *);
void (*lm_get_owner)(struct file_lock *, struct file_lock *);
void (*lm_put_owner)(struct file_lock *);
void (*lm_notify)(struct file_lock *); /* unblock callback */
int (*lm_grant)(struct file_lock *, struct file_lock *, int);
void (*lm_break)(struct file_lock *);
int (*lm_change)(struct file_lock **, int);
int (*lm_grant)(struct file_lock *, int);
bool (*lm_break)(struct file_lock *);
int (*lm_change)(struct file_lock **, int, struct list_head *);
void (*lm_setup)(struct file_lock *, void **);
};
struct lock_manager {
@ -966,7 +963,7 @@ void locks_free_lock(struct file_lock *fl);
extern void locks_init_lock(struct file_lock *);
extern struct file_lock * locks_alloc_lock(void);
extern void locks_copy_lock(struct file_lock *, struct file_lock *);
extern void __locks_copy_lock(struct file_lock *, const struct file_lock *);
extern void locks_copy_conflock(struct file_lock *, struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t);
extern void locks_remove_file(struct file *);
extern void locks_release_private(struct file_lock *);
@ -980,11 +977,9 @@ 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 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 **);
extern int vfs_setlease(struct file *, long, struct file_lock **);
extern int lease_modify(struct file_lock **, int);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
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 *);
#else /* !CONFIG_FILE_LOCKING */
static inline int fcntl_getlk(struct file *file, unsigned int cmd,
struct flock __user *user)
@ -1013,12 +1008,12 @@ static inline int fcntl_setlk64(unsigned int fd, struct file *file,
#endif
static inline int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{
return 0;
return -EINVAL;
}
static inline int fcntl_getlease(struct file *filp)
{
return 0;
return F_UNLCK;
}
static inline void locks_init_lock(struct file_lock *fl)
@ -1026,7 +1021,7 @@ static inline void locks_init_lock(struct file_lock *fl)
return;
}
static inline void __locks_copy_lock(struct file_lock *new, struct file_lock *fl)
static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
{
return;
}
@ -1100,33 +1095,22 @@ static inline void lease_get_mtime(struct inode *inode, struct timespec *time)
}
static inline int generic_setlease(struct file *filp, long arg,
struct file_lock **flp)
struct file_lock **flp, void **priv)
{
return -EINVAL;
}
static inline int vfs_setlease(struct file *filp, long arg,
struct file_lock **lease)
struct file_lock **lease, void **priv)
{
return -EINVAL;
}
static inline int lease_modify(struct file_lock **before, int arg)
static inline int lease_modify(struct file_lock **before, int arg,
struct list_head *dispose)
{
return -EINVAL;
}
static inline int lock_may_read(struct inode *inode, loff_t start,
unsigned long len)
{
return 1;
}
static inline int lock_may_write(struct inode *inode, loff_t start,
unsigned long len)
{
return 1;
}
#endif /* !CONFIG_FILE_LOCKING */
@ -1151,8 +1135,8 @@ extern void fasync_free(struct fasync_struct *);
/* can be called from interrupts */
extern void kill_fasync(struct fasync_struct **, int, int);
extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
extern int f_setown(struct file *filp, unsigned long arg, int force);
extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
extern void f_setown(struct file *filp, unsigned long arg, int force);
extern void f_delown(struct file *filp);
extern pid_t f_getown(struct file *filp);
extern int send_sigurg(struct fown_struct *fown);
@ -1506,7 +1490,7 @@ struct file_operations {
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
int (*setlease)(struct file *, long, struct file_lock **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
int (*show_fdinfo)(struct seq_file *m, struct file *f);
@ -2611,6 +2595,7 @@ extern int simple_write_end(struct file *file, struct address_space *mapping,
struct page *page, void *fsdata);
extern int always_delete_dentry(const struct dentry *);
extern struct inode *alloc_anon_inode(struct super_block *);
extern int simple_nosetlease(struct file *, long, struct file_lock **, void **);
extern const struct dentry_operations simple_dentry_operations;
extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);

View File

@ -178,7 +178,6 @@ struct nlm_block {
unsigned char b_granted; /* VFS granted lock */
struct nlm_file * b_file; /* file in question */
struct cache_req * b_cache_req; /* deferred request handling */
struct file_lock * b_fl; /* set for GETLK */
struct cache_deferred_req * b_deferred_req;
unsigned int b_flags; /* block flags */
#define B_QUEUED 1 /* lock queued */

View File

@ -1559,7 +1559,7 @@ struct security_operations {
int (*file_lock) (struct file *file, unsigned int cmd);
int (*file_fcntl) (struct file *file, unsigned int cmd,
unsigned long arg);
int (*file_set_fowner) (struct file *file);
void (*file_set_fowner) (struct file *file);
int (*file_send_sigiotask) (struct task_struct *tsk,
struct fown_struct *fown, int sig);
int (*file_receive) (struct file *file);
@ -1834,7 +1834,7 @@ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
unsigned long prot);
int security_file_lock(struct file *file, unsigned int cmd);
int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg);
int security_file_set_fowner(struct file *file);
void security_file_set_fowner(struct file *file);
int security_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int sig);
int security_file_receive(struct file *file);
@ -2312,9 +2312,9 @@ static inline int security_file_fcntl(struct file *file, unsigned int cmd,
return 0;
}
static inline int security_file_set_fowner(struct file *file)
static inline void security_file_set_fowner(struct file *file)
{
return 0;
return;
}
static inline int security_file_send_sigiotask(struct task_struct *tsk,

View File

@ -53,15 +53,15 @@ DECLARE_EVENT_CLASS(filelock_lease,
),
TP_fast_assign(
__entry->fl = fl;
__entry->fl = fl ? fl : NULL;
__entry->s_dev = inode->i_sb->s_dev;
__entry->i_ino = inode->i_ino;
__entry->fl_next = fl->fl_next;
__entry->fl_owner = fl->fl_owner;
__entry->fl_flags = fl->fl_flags;
__entry->fl_type = fl->fl_type;
__entry->fl_break_time = fl->fl_break_time;
__entry->fl_downgrade_time = fl->fl_downgrade_time;
__entry->fl_next = fl ? fl->fl_next : NULL;
__entry->fl_owner = fl ? fl->fl_owner : NULL;
__entry->fl_flags = fl ? fl->fl_flags : 0;
__entry->fl_type = fl ? fl->fl_type : 0;
__entry->fl_break_time = fl ? fl->fl_break_time : 0;
__entry->fl_downgrade_time = fl ? fl->fl_downgrade_time : 0;
),
TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_next=0x%p fl_owner=0x%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu",

View File

@ -1065,7 +1065,8 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
err = -EFAULT;
if (get_user(pid, (int __user *)argp))
break;
err = f_setown(sock->file, pid, 1);
f_setown(sock->file, pid, 1);
err = 0;
break;
case FIOGETOWN:
case SIOCGPGRP:

View File

@ -343,9 +343,9 @@ static int cap_file_fcntl(struct file *file, unsigned int cmd,
return 0;
}
static int cap_file_set_fowner(struct file *file)
static void cap_file_set_fowner(struct file *file)
{
return 0;
return;
}
static int cap_file_send_sigiotask(struct task_struct *tsk,

View File

@ -775,9 +775,9 @@ int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
return security_ops->file_fcntl(file, cmd, arg);
}
int security_file_set_fowner(struct file *file)
void security_file_set_fowner(struct file *file)
{
return security_ops->file_set_fowner(file);
security_ops->file_set_fowner(file);
}
int security_file_send_sigiotask(struct task_struct *tsk,

View File

@ -3346,14 +3346,12 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
return err;
}
static int selinux_file_set_fowner(struct file *file)
static void selinux_file_set_fowner(struct file *file)
{
struct file_security_struct *fsec;
fsec = file->f_security;
fsec->fown_sid = current_sid();
return 0;
}
static int selinux_file_send_sigiotask(struct task_struct *tsk,

View File

@ -1390,12 +1390,11 @@ static int smack_mmap_file(struct file *file,
* Returns 0
* Further research may be required on this one.
*/
static int smack_file_set_fowner(struct file *file)
static void smack_file_set_fowner(struct file *file)
{
struct smack_known *skp = smk_of_current();
file->f_security = skp->smk_known;
return 0;
}
/**