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); size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,
size_t, unsigned int); 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); long (*fallocate)(struct file *, int, loff_t, loff_t);
}; };
locking rules: locking rules:
All may block except for ->setlease. All may block.
No VFS locks held on entry except for ->setlease.
->setlease has the file_list_lock held and must not sleep.
->llseek() locking has moved from llseek to the individual llseek ->llseek() locking has moved from llseek to the individual llseek
implementations. If your fs is not using generic_file_llseek, you 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 ->read on directories probably must go away - we should just enforce -EISDIR
in sys_read() and friends. 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 ------------------------------- --------------------------- dquot_operations -------------------------------
prototypes: prototypes:
int (*write_dquot) (struct dquot *); int (*write_dquot) (struct dquot *);

View file

@ -826,7 +826,7 @@ struct file_operations {
int (*flock) (struct file *, int, struct file_lock *); 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_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); 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); long (*fallocate)(struct file *, int mode, loff_t offset, loff_t len);
int (*show_fdinfo)(struct seq_file *m, struct file *f); 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 splice_read: called by the VFS to splice data from file to a pipe. This
method is used by the splice(2) system call method is used by the splice(2) system call
setlease: called by the VFS to set or release a file lock lease. setlease: called by the VFS to set or release a file lock lease. setlease
setlease has the file_lock_lock held and must not sleep. 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. 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; goto out;
if (on) { if (on) {
ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0); __f_setown(file, task_pid(current), PIDTYPE_PID, 0);
if (ret)
goto out;
tfile->flags |= TUN_FASYNC; tfile->flags |= TUN_FASYNC;
} else } else
tfile->flags &= ~TUN_FASYNC; tfile->flags &= ~TUN_FASYNC;

View file

@ -2186,8 +2186,9 @@ static int __tty_fasync(int fd, struct file *filp, int on)
} }
get_pid(pid); get_pid(pid);
spin_unlock_irqrestore(&tty->ctrl_lock, flags); spin_unlock_irqrestore(&tty->ctrl_lock, flags);
retval = __f_setown(filp, pid, type, 0); __f_setown(filp, pid, type, 0);
put_pid(pid); put_pid(pid);
retval = 0;
} }
out: out:
return retval; 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); 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 * 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 || if (arg == F_UNLCK ||
((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) || ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
((arg == F_WRLCK) && CIFS_CACHE_WRITE(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 && else if (tlink_tcon(cfile->tlink)->local_lease &&
!CIFS_CACHE_READ(CIFS_I(inode))) !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 * knows that the file won't be changed on the server by anyone
* else. * else.
*/ */
return generic_setlease(file, arg, lease); return generic_setlease(file, arg, lease, priv);
else else
return -EAGAIN; return -EAGAIN;
} }

View file

@ -30,7 +30,7 @@ struct plock_op {
struct plock_xop { struct plock_xop {
struct plock_op xop; struct plock_op xop;
void *callback; int (*callback)(struct file_lock *fl, int result);
void *fl; void *fl;
void *file; void *file;
struct file_lock flc; struct file_lock flc;
@ -190,7 +190,7 @@ static int dlm_plock_callback(struct plock_op *op)
struct file *file; struct file *file;
struct file_lock *fl; struct file_lock *fl;
struct file_lock *flc; 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; struct plock_xop *xop = (struct plock_xop *)op;
int rv = 0; int rv = 0;
@ -209,7 +209,7 @@ static int dlm_plock_callback(struct plock_op *op)
notify = xop->callback; notify = xop->callback;
if (op->info.rv) { if (op->info.rv) {
notify(fl, NULL, op->info.rv); notify(fl, op->info.rv);
goto out; goto out;
} }
@ -228,7 +228,7 @@ static int dlm_plock_callback(struct plock_op *op)
(unsigned long long)op->info.number, file, fl); (unsigned long long)op->info.number, file, fl);
} }
rv = notify(fl, NULL, 0); rv = notify(fl, 0);
if (rv) { if (rv) {
/* XXX: We need to cancel the fs lock here: */ /* XXX: We need to cancel the fs lock here: */
log_print("dlm_plock_callback: lock granted after lock request " 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); 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 force)
{ {
int err; security_file_set_fowner(filp);
err = security_file_set_fowner(filp);
if (err)
return err;
f_modown(filp, pid, type, force); f_modown(filp, pid, type, force);
return 0;
} }
EXPORT_SYMBOL(__f_setown); 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; enum pid_type type;
struct pid *pid; struct pid *pid;
int who = arg; int who = arg;
int result;
type = PIDTYPE_PID; type = PIDTYPE_PID;
if (who < 0) { if (who < 0) {
type = PIDTYPE_PGID; type = PIDTYPE_PGID;
@ -125,9 +118,8 @@ int f_setown(struct file *filp, unsigned long arg, int force)
} }
rcu_read_lock(); rcu_read_lock();
pid = find_vpid(who); pid = find_vpid(who);
result = __f_setown(filp, pid, type, force); __f_setown(filp, pid, type, force);
rcu_read_unlock(); rcu_read_unlock();
return result;
} }
EXPORT_SYMBOL(f_setown); EXPORT_SYMBOL(f_setown);
@ -181,7 +173,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg)
if (owner.pid && !pid) if (owner.pid && !pid)
ret = -ESRCH; ret = -ESRCH;
else else
ret = __f_setown(filp, pid, type, 1); __f_setown(filp, pid, type, 1);
rcu_read_unlock(); rcu_read_unlock();
return ret; return ret;
@ -302,7 +294,8 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
force_successful_syscall_return(); force_successful_syscall_return();
break; break;
case F_SETOWN: case F_SETOWN:
err = f_setown(filp, arg, 1); f_setown(filp, arg, 1);
err = 0;
break; break;
case F_GETOWN_EX: case F_GETOWN_EX:
err = f_getown_ex(filp, arg); err = f_getown_ex(filp, arg);

View file

@ -913,26 +913,6 @@ out_uninit:
#ifdef CONFIG_GFS2_FS_LOCKING_DLM #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 * gfs2_lock - acquire/release a posix lock on a file
* @file: the file pointer * @file: the file pointer
@ -1078,7 +1058,7 @@ const struct file_operations gfs2_file_fops = {
.flock = gfs2_flock, .flock = gfs2_flock,
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write, .splice_write = iter_file_splice_write,
.setlease = gfs2_setlease, .setlease = simple_nosetlease,
.fallocate = gfs2_fallocate, .fallocate = gfs2_fallocate,
}; };

View file

@ -1075,3 +1075,21 @@ struct inode *alloc_anon_inode(struct super_block *s)
return inode; return inode;
} }
EXPORT_SYMBOL(alloc_anon_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_daemon = rqstp->rq_server;
block->b_host = host; block->b_host = host;
block->b_file = file; block->b_file = file;
block->b_fl = NULL;
file->f_count++; file->f_count++;
/* Add to file's list of blocks */ /* 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_freegrantargs(block->b_call);
nlmsvc_release_call(block->b_call); nlmsvc_release_call(block->b_call);
nlm_release_file(block->b_file); nlm_release_file(block->b_file);
kfree(block->b_fl);
kfree(block); 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_host *host, struct nlm_lock *lock,
struct nlm_lock *conflock, struct nlm_cookie *cookie) struct nlm_lock *conflock, struct nlm_cookie *cookie)
{ {
struct nlm_block *block = NULL;
int error; int error;
__be32 ret; __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_start,
(long long)lock->fl.fl_end); (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))) { if (locks_in_grace(SVC_NET(rqstp))) {
ret = nlm_lck_denied_grace_period; ret = nlm_lck_denied_grace_period;
goto out; goto out;
} }
error = vfs_test_lock(file->f_file, &lock->fl); 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) { 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; ret = nlm_lck_denied_nolocks;
goto out; goto out;
} }
if (lock->fl.fl_type == F_UNLCK) { if (lock->fl.fl_type == F_UNLCK) {
ret = nlm_granted; ret = nlm_granted;
goto out; goto out;
} }
conf_lock:
dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
lock->fl.fl_type, (long long)lock->fl.fl_start, lock->fl.fl_type, (long long)lock->fl.fl_start,
(long long)lock->fl.fl_end); (long long)lock->fl.fl_end);
@ -586,10 +546,9 @@ conf_lock:
conflock->fl.fl_type = lock->fl.fl_type; conflock->fl.fl_type = lock->fl.fl_type;
conflock->fl.fl_start = lock->fl.fl_start; conflock->fl.fl_start = lock->fl.fl_start;
conflock->fl.fl_end = lock->fl.fl_end; conflock->fl.fl_end = lock->fl.fl_end;
locks_release_private(&lock->fl);
ret = nlm_lck_denied; ret = nlm_lck_denied;
out: out:
if (block)
nlmsvc_release_block(block);
return ret; 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. * 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 * It will be used if lm_grant is defined and the filesystem can not
* respond to the request immediately. * 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. * 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 * 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 * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
* deferred rpc for GETLK and SETLK. * deferred rpc for GETLK and SETLK.
*/ */
static void static void
nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf, nlmsvc_update_deferred_block(struct nlm_block *block, int result)
int result)
{ {
block->b_flags |= B_GOT_CALLBACK; block->b_flags |= B_GOT_CALLBACK;
if (result == 0) if (result == 0)
block->b_granted = 1; block->b_granted = 1;
else else
block->b_flags |= B_TIMED_OUT; 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, static int nlmsvc_grant_deferred(struct file_lock *fl, int result)
int result)
{ {
struct nlm_block *block; struct nlm_block *block;
int rc = -ENOENT; int rc = -ENOENT;
@ -697,7 +649,7 @@ static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
rc = -ENOLCK; rc = -ENOLCK;
break; break;
} }
nlmsvc_update_deferred_block(block, conf, result); nlmsvc_update_deferred_block(block, result);
} else if (result == 0) } else if (result == 0)
block->b_granted = 1; 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->fl_release_private(fl);
fl->fl_ops = NULL; 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); EXPORT_SYMBOL_GPL(locks_release_private);
@ -267,21 +271,10 @@ void locks_init_lock(struct file_lock *fl)
EXPORT_SYMBOL(locks_init_lock); 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. * 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_owner = fl->fl_owner;
new->fl_pid = fl->fl_pid; 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_type = fl->fl_type;
new->fl_start = fl->fl_start; new->fl_start = fl->fl_start;
new->fl_end = fl->fl_end; new->fl_end = fl->fl_end;
new->fl_lmops = fl->fl_lmops;
new->fl_ops = NULL; 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) void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
{ {
/* "new" must be a freshly-initialized lock */ /* "new" must be a freshly-initialized lock */
WARN_ON_ONCE(new->fl_ops); WARN_ON_ONCE(new->fl_ops);
__locks_copy_lock(new, fl); locks_copy_conflock(new, fl);
new->fl_file = fl->fl_file; new->fl_file = fl->fl_file;
new->fl_ops = fl->fl_ops; 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); 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. */ /* Fill in a file_lock structure with an appropriate FLOCK lock. */
static int flock_make_lock(struct file *filp, struct file_lock **lock, static struct file_lock *
unsigned int cmd) flock_make_lock(struct file *filp, unsigned int cmd)
{ {
struct file_lock *fl; struct file_lock *fl;
int type = flock_translate_cmd(cmd); int type = flock_translate_cmd(cmd);
if (type < 0) if (type < 0)
return type; return ERR_PTR(type);
fl = locks_alloc_lock(); fl = locks_alloc_lock();
if (fl == NULL) if (fl == NULL)
return -ENOMEM; return ERR_PTR(-ENOMEM);
fl->fl_file = filp; fl->fl_file = filp;
fl->fl_owner = 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_type = type;
fl->fl_end = OFFSET_MAX; fl->fl_end = OFFSET_MAX;
*lock = fl; return fl;
return 0;
} }
static int assign_type(struct file_lock *fl, long type) 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 */ /* 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); 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 = { static const struct lock_manager_operations lease_manager_ops = {
.lm_break = lease_break_callback, .lm_break = lease_break_callback,
.lm_change = lease_modify, .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) if (assign_type(fl, type) != 0)
return -EINVAL; return -EINVAL;
fl->fl_owner = current->files; fl->fl_owner = filp;
fl->fl_pid = current->tgid; fl->fl_pid = current->tgid;
fl->fl_file = filp; fl->fl_file = filp;
@ -735,7 +756,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
break; break;
} }
if (cfl) { if (cfl) {
__locks_copy_lock(fl, cfl); locks_copy_conflock(fl, cfl);
if (cfl->fl_nspid) if (cfl->fl_nspid)
fl->fl_pid = pid_vnr(cfl->fl_nspid); fl->fl_pid = pid_vnr(cfl->fl_nspid);
} else } else
@ -941,7 +962,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
if (!posix_locks_conflict(request, fl)) if (!posix_locks_conflict(request, fl))
continue; continue;
if (conflock) if (conflock)
__locks_copy_lock(conflock, fl); locks_copy_conflock(conflock, fl);
error = -EAGAIN; error = -EAGAIN;
if (!(request->fl_flags & FL_SLEEP)) if (!(request->fl_flags & FL_SLEEP))
goto out; 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 */ /* 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; struct file_lock *fl = *before;
int error = assign_type(fl, arg); 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); printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
fl->fl_fasync = NULL; fl->fl_fasync = NULL;
} }
locks_delete_lock(before, NULL); locks_delete_lock(before, dispose);
} }
return 0; return 0;
} }
EXPORT_SYMBOL(lease_modify); EXPORT_SYMBOL(lease_modify);
static bool past_time(unsigned long then) static bool past_time(unsigned long then)
@ -1307,18 +1327,20 @@ static bool past_time(unsigned long then)
return time_after(jiffies, 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 **before;
struct file_lock *fl; struct file_lock *fl;
lockdep_assert_held(&inode->i_lock);
before = &inode->i_flock; before = &inode->i_flock;
while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) { while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) {
trace_time_out_leases(inode, fl); trace_time_out_leases(inode, fl);
if (past_time(fl->fl_downgrade_time)) 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)) 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 */ if (fl == *before) /* lease_modify may have freed fl */
before = &fl->fl_next; 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); 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 * __break_lease - revoke all outstanding leases on file
* @inode: the inode of the file to return * @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 __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
{ {
int error = 0; int error = 0;
struct file_lock *new_fl, *flock; struct file_lock *new_fl;
struct file_lock *fl; struct file_lock *fl, **before;
unsigned long break_time; unsigned long break_time;
int i_have_this_lease = 0;
bool lease_conflict = false;
int want_write = (mode & O_ACCMODE) != O_RDONLY; int want_write = (mode & O_ACCMODE) != O_RDONLY;
LIST_HEAD(dispose);
new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK);
if (IS_ERR(new_fl)) 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); spin_lock(&inode->i_lock);
time_out_leases(inode); time_out_leases(inode, &dispose);
flock = inode->i_flock; if (!any_leases_conflict(inode, new_fl))
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)
goto out; goto out;
break_time = 0; 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 */ 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)) if (!leases_conflict(fl, new_fl))
continue; continue;
if (want_write) { 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_flags |= FL_UNLOCK_PENDING;
fl->fl_break_time = break_time; fl->fl_break_time = break_time;
} else { } else {
if (lease_breaking(flock)) if (lease_breaking(inode->i_flock))
continue; continue;
fl->fl_flags |= FL_DOWNGRADE_PENDING; fl->fl_flags |= FL_DOWNGRADE_PENDING;
fl->fl_downgrade_time = break_time; 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); trace_break_lease_noblock(inode, new_fl);
error = -EWOULDBLOCK; error = -EWOULDBLOCK;
goto out; goto out;
} }
restart: restart:
break_time = flock->fl_break_time; break_time = inode->i_flock->fl_break_time;
if (break_time != 0) if (break_time != 0)
break_time -= jiffies; break_time -= jiffies;
if (break_time == 0) if (break_time == 0)
break_time++; break_time++;
locks_insert_block(flock, new_fl); locks_insert_block(inode->i_flock, new_fl);
trace_break_lease_block(inode, new_fl); trace_break_lease_block(inode, new_fl);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
locks_dispose_list(&dispose);
error = wait_event_interruptible_timeout(new_fl->fl_wait, error = wait_event_interruptible_timeout(new_fl->fl_wait,
!new_fl->fl_next, break_time); !new_fl->fl_next, break_time);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
trace_break_lease_unblock(inode, new_fl); trace_break_lease_unblock(inode, new_fl);
locks_delete_block(new_fl); locks_delete_block(new_fl);
if (error >= 0) { if (error >= 0) {
if (error == 0)
time_out_leases(inode);
/* /*
* Wait for the next conflicting lease that has not been * Wait for the next conflicting lease that has not been
* broken yet * broken yet
*/ */
for (flock = inode->i_flock; flock && IS_LEASE(flock); if (error == 0)
flock = flock->fl_next) { time_out_leases(inode, &dispose);
if (leases_conflict(new_fl, flock)) if (any_leases_conflict(inode, new_fl))
goto restart; goto restart;
}
error = 0; error = 0;
} }
out: out:
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
locks_dispose_list(&dispose);
locks_free_lock(new_fl); locks_free_lock(new_fl);
return error; return error;
} }
@ -1455,8 +1486,18 @@ EXPORT_SYMBOL(__break_lease);
*/ */
void lease_get_mtime(struct inode *inode, struct timespec *time) void lease_get_mtime(struct inode *inode, struct timespec *time)
{ {
struct file_lock *flock = inode->i_flock; bool has_lease = false;
if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK)) 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); *time = current_fs_time(inode->i_sb);
else else
*time = inode->i_mtime; *time = inode->i_mtime;
@ -1492,9 +1533,10 @@ int fcntl_getlease(struct file *filp)
struct file_lock *fl; struct file_lock *fl;
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
int type = F_UNLCK; int type = F_UNLCK;
LIST_HEAD(dispose);
spin_lock(&inode->i_lock); 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); for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl);
fl = fl->fl_next) { fl = fl->fl_next) {
if (fl->fl_file == filp) { if (fl->fl_file == filp) {
@ -1503,6 +1545,7 @@ int fcntl_getlease(struct file *filp)
} }
} }
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
locks_dispose_list(&dispose);
return type; return type;
} }
@ -1532,13 +1575,15 @@ check_conflicting_open(const struct dentry *dentry, const long arg)
return ret; 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 file_lock *fl, **before, **my_before = NULL, *lease;
struct dentry *dentry = filp->f_path.dentry; struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
bool is_deleg = (*flp)->fl_flags & FL_DELEG; bool is_deleg = (*flp)->fl_flags & FL_DELEG;
int error; int error;
LIST_HEAD(dispose);
lease = *flp; lease = *flp;
trace_generic_add_lease(inode, lease); 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; return -EINVAL;
} }
spin_lock(&inode->i_lock);
time_out_leases(inode, &dispose);
error = check_conflicting_open(dentry, arg); error = check_conflicting_open(dentry, arg);
if (error) if (error)
goto out; goto out;
@ -1596,10 +1643,11 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
} }
if (my_before != NULL) { if (my_before != NULL) {
error = lease->fl_lmops->lm_change(my_before, arg); lease = *my_before;
if (!error) error = lease->fl_lmops->lm_change(my_before, arg, &dispose);
*flp = *my_before; if (error)
goto out; goto out;
goto out_setup;
} }
error = -EINVAL; error = -EINVAL;
@ -1619,43 +1667,61 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
smp_mb(); smp_mb();
error = check_conflicting_open(dentry, arg); error = check_conflicting_open(dentry, arg);
if (error) 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: out:
spin_unlock(&inode->i_lock);
locks_dispose_list(&dispose);
if (is_deleg) if (is_deleg)
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (!error && !my_before)
*flp = NULL;
return error; 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 file_lock *fl, **before;
struct dentry *dentry = filp->f_path.dentry; struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode; 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; for (before = &inode->i_flock;
((fl = *before) != NULL) && IS_LEASE(fl); ((fl = *before) != NULL) && IS_LEASE(fl);
before = &fl->fl_next) { before = &fl->fl_next) {
if (fl->fl_file != filp) if (fl->fl_file == filp)
continue; break;
return (*flp)->fl_lmops->lm_change(before, F_UNLCK);
} }
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;
} }
/** /**
* generic_setlease - sets a lease on an open file * generic_setlease - sets a lease on an open file
* @filp: file pointer * @filp: file pointer
* @arg: type of lease to obtain * @arg: type of lease to obtain
* @flp: input - file_lock to use, output - file_lock inserted * @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 * The (input) flp->fl_lmops->lm_break function is required
* by break_lease(). * 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 dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
@ -1669,83 +1735,52 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
if (error) if (error)
return error; return error;
time_out_leases(inode);
BUG_ON(!(*flp)->fl_lmops->lm_break);
switch (arg) { switch (arg) {
case F_UNLCK: case F_UNLCK:
return generic_delete_lease(filp, flp); return generic_delete_lease(filp);
case F_RDLCK: case F_RDLCK:
case F_WRLCK: 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: default:
return -EINVAL; return -EINVAL;
} }
} }
EXPORT_SYMBOL(generic_setlease); EXPORT_SYMBOL(generic_setlease);
static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease) /**
* vfs_setlease - sets a lease on an open file
* @filp: file pointer
* @arg: type of lease to obtain
* @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" 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).
*
* 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, void **priv)
{ {
if (filp->f_op->setlease) if (filp->f_op->setlease)
return filp->f_op->setlease(filp, arg, lease); return filp->f_op->setlease(filp, arg, lease, priv);
else else
return generic_setlease(filp, arg, lease); return generic_setlease(filp, arg, lease, priv);
}
/**
* vfs_setlease - sets a lease on an open file
* @filp: file pointer
* @arg: type of lease to obtain
* @lease: file_lock to use
*
* 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!
*
* 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.
*/
int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
{
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;
} }
EXPORT_SYMBOL_GPL(vfs_setlease); 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) static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
{ {
struct file_lock *fl, *ret; struct file_lock *fl;
struct inode *inode = file_inode(filp);
struct fasync_struct *new; struct fasync_struct *new;
int error; int error;
@ -1758,26 +1793,9 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
locks_free_lock(fl); locks_free_lock(fl);
return -ENOMEM; return -ENOMEM;
} }
ret = fl; new->fa_fd = fd;
spin_lock(&inode->i_lock);
error = __vfs_setlease(filp, arg, &ret);
if (error)
goto out_unlock;
if (ret == fl)
fl = NULL;
/* error = vfs_setlease(filp, arg, &fl, (void **)&new);
* 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);
if (fl) if (fl)
locks_free_lock(fl); locks_free_lock(fl);
if (new) if (new)
@ -1798,7 +1816,7 @@ out_unlock:
int fcntl_setlease(unsigned int fd, struct file *filp, long arg) int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{ {
if (arg == F_UNLCK) 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); 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))) !(f.file->f_mode & (FMODE_READ|FMODE_WRITE)))
goto out_putf; goto out_putf;
error = flock_make_lock(f.file, &lock, cmd); lock = flock_make_lock(f.file, cmd);
if (error) if (IS_ERR(lock)) {
error = PTR_ERR(lock);
goto out_putf; goto out_putf;
}
if (can_sleep) if (can_sleep)
lock->fl_flags |= FL_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) { if (file_lock.fl_type != F_UNLCK) {
error = posix_lock_to_flock(&flock, &file_lock); error = posix_lock_to_flock(&flock, &file_lock);
if (error) if (error)
goto out; goto rel_priv;
} }
error = -EFAULT; error = -EFAULT;
if (!copy_to_user(l, &flock, sizeof(flock))) if (!copy_to_user(l, &flock, sizeof(flock)))
error = 0; error = 0;
rel_priv:
locks_release_private(&file_lock);
out: out:
return error; return error;
} }
@ -2206,7 +2229,8 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
error = -EFAULT; error = -EFAULT;
if (!copy_to_user(l, &flock, sizeof(flock))) if (!copy_to_user(l, &flock, sizeof(flock)))
error = 0; error = 0;
locks_release_private(&file_lock);
out: out:
return error; return error;
} }
@ -2369,7 +2393,7 @@ void locks_remove_file(struct file *filp)
while ((fl = *before) != NULL) { while ((fl = *before) != NULL) {
if (fl->fl_file == filp) { if (fl->fl_file == filp) {
if (IS_LEASE(fl)) { if (IS_LEASE(fl)) {
lease_modify(before, F_UNLCK); lease_modify(before, F_UNLCK, &dispose);
continue; continue;
} }
@ -2593,86 +2617,6 @@ static int __init proc_locks_init(void)
module_init(proc_locks_init); module_init(proc_locks_init);
#endif #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) static int __init filelock_init(void)
{ {
int i; 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); 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 = { const struct file_operations nfs_file_operations = {
.llseek = nfs_file_llseek, .llseek = nfs_file_llseek,
.read = new_sync_read, .read = new_sync_read,
@ -946,6 +935,6 @@ const struct file_operations nfs_file_operations = {
.splice_read = nfs_file_splice_read, .splice_read = nfs_file_splice_read,
.splice_write = iter_file_splice_write, .splice_write = iter_file_splice_write,
.check_flags = nfs_check_flags, .check_flags = nfs_check_flags,
.setlease = nfs_setlease, .setlease = simple_nosetlease,
}; };
EXPORT_SYMBOL_GPL(nfs_file_operations); 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_lock(struct file *, int, struct file_lock *);
int nfs_flock(struct file *, int, struct file_lock *); int nfs_flock(struct file *, int, struct file_lock *);
int nfs_check_flags(int); int nfs_check_flags(int);
int nfs_setlease(struct file *, long, struct file_lock **);
/* inode.c */ /* inode.c */
extern struct workqueue_struct *nfsiod_workqueue; 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_read = nfs_file_splice_read,
.splice_write = iter_file_splice_write, .splice_write = iter_file_splice_write,
.check_flags = nfs_check_flags, .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); 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 static int
same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) 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) { so_strhash) {
if (!so->so_is_open_owner) if (!so->so_is_open_owner)
continue; continue;
if (same_owner_str(so, &open->op_owner)) { if (same_owner_str(so, &open->op_owner))
atomic_inc(&so->so_count); return openowner(nfs4_get_stateowner(so));
return openowner(so);
}
} }
return NULL; return NULL;
} }
@ -678,18 +683,14 @@ nfs4_put_stid(struct nfs4_stid *s)
static void nfs4_put_deleg_lease(struct nfs4_file *fp) static void nfs4_put_deleg_lease(struct nfs4_file *fp)
{ {
struct file *filp = NULL; struct file *filp = NULL;
struct file_lock *fl;
spin_lock(&fp->fi_lock); 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); swap(filp, fp->fi_deleg_file);
fl = fp->fi_lease;
fp->fi_lease = NULL;
}
spin_unlock(&fp->fi_lock); spin_unlock(&fp->fi_lock);
if (filp) { if (filp) {
vfs_setlease(filp, F_UNLCK, &fl); vfs_setlease(filp, F_UNLCK, NULL, NULL);
fput(filp); fput(filp);
} }
} }
@ -1655,7 +1656,7 @@ __destroy_client(struct nfs4_client *clp)
} }
while (!list_empty(&clp->cl_openowners)) { while (!list_empty(&clp->cl_openowners)) {
oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 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); release_openowner(oo);
} }
nfsd4_shutdown_callback(clp); 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_stateids);
INIT_LIST_HEAD(&fp->fi_delegations); INIT_LIST_HEAD(&fp->fi_delegations);
fh_copy_shallow(&fp->fi_fhandle, fh); fh_copy_shallow(&fp->fi_fhandle, fh);
fp->fi_deleg_file = NULL;
fp->fi_had_conflict = false; fp->fi_had_conflict = false;
fp->fi_lease = NULL;
fp->fi_share_deny = 0; fp->fi_share_deny = 0;
memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
memset(fp->fi_access, 0, sizeof(fp->fi_access)); 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)) { if (!nfsd4_has_session(cstate)) {
mutex_lock(&so->so_replay.rp_mutex); mutex_lock(&so->so_replay.rp_mutex);
cstate->replay_owner = so; cstate->replay_owner = nfs4_get_stateowner(so);
atomic_inc(&so->so_count);
} }
} }
@ -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); atomic_inc(&stp->st_stid.sc_count);
stp->st_stid.sc_type = NFS4_OPEN_STID; stp->st_stid.sc_type = NFS4_OPEN_STID;
INIT_LIST_HEAD(&stp->st_locks); INIT_LIST_HEAD(&stp->st_locks);
stp->st_stateowner = &oo->oo_owner; stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner);
atomic_inc(&stp->st_stateowner->so_count);
get_nfs4_file(fp); get_nfs4_file(fp);
stp->st_stid.sc_file = fp; stp->st_stid.sc_file = fp;
stp->st_access_bmap = 0; 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. */ /* 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_file *fp = (struct nfs4_file *)fl->fl_owner;
struct nfs4_delegation *dp; struct nfs4_delegation *dp;
if (!fp) { if (!fp) {
WARN(1, "(%p)->fl_owner NULL\n", fl); WARN(1, "(%p)->fl_owner NULL\n", fl);
return; return ret;
} }
if (fp->fi_had_conflict) { if (fp->fi_had_conflict) {
WARN(1, "duplicate break on %p\n", fp); WARN(1, "duplicate break on %p\n", fp);
return; return ret;
} }
/* /*
* We don't want the locks code to timeout the lease for us; * 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); spin_lock(&fp->fi_lock);
fp->fi_had_conflict = true; fp->fi_had_conflict = true;
/* /*
* If there are no delegations on the list, then we can't count on this * If there are no delegations on the list, then return true
* lease ever being cleaned up. Set the fl_break_time to jiffies so that * so that the lease code will go ahead and delete it.
* 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 (list_empty(&fp->fi_delegations)) if (list_empty(&fp->fi_delegations))
fl->fl_break_time = jiffies; ret = true;
else else
list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
nfsd_break_one_deleg(dp); nfsd_break_one_deleg(dp);
spin_unlock(&fp->fi_lock); spin_unlock(&fp->fi_lock);
return ret;
} }
static static int
int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) nfsd_change_deleg_cb(struct file_lock **onlist, int arg, struct list_head *dispose)
{ {
if (arg & F_UNLCK) if (arg & F_UNLCK)
return lease_modify(onlist, arg); return lease_modify(onlist, arg, dispose);
else else
return -EAGAIN; 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) static int nfs4_setlease(struct nfs4_delegation *dp)
{ {
struct nfs4_file *fp = dp->dl_stid.sc_file; struct nfs4_file *fp = dp->dl_stid.sc_file;
struct file_lock *fl; struct file_lock *fl, *ret;
struct file *filp; struct file *filp;
int status = 0; int status = 0;
@ -3834,11 +3834,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
return -EBADF; return -EBADF;
} }
fl->fl_file = filp; fl->fl_file = filp;
status = vfs_setlease(filp, fl->fl_type, &fl); ret = fl;
if (status) { status = vfs_setlease(filp, fl->fl_type, &fl, NULL);
if (fl)
locks_free_lock(fl); locks_free_lock(fl);
if (status)
goto out_fput; goto out_fput;
}
spin_lock(&state_lock); spin_lock(&state_lock);
spin_lock(&fp->fi_lock); spin_lock(&fp->fi_lock);
/* Did the lease get broken before we took the 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) if (fp->fi_had_conflict)
goto out_unlock; goto out_unlock;
/* Race breaker */ /* Race breaker */
if (fp->fi_lease) { if (fp->fi_deleg_file) {
status = 0; status = 0;
atomic_inc(&fp->fi_delegees); atomic_inc(&fp->fi_delegees);
hash_delegation_locked(dp, fp); hash_delegation_locked(dp, fp);
goto out_unlock; goto out_unlock;
} }
fp->fi_lease = fl;
fp->fi_deleg_file = filp; fp->fi_deleg_file = filp;
atomic_set(&fp->fi_delegees, 1); atomic_set(&fp->fi_delegees, 1);
hash_delegation_locked(dp, fp); 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(&state_lock);
spin_lock(&fp->fi_lock); spin_lock(&fp->fi_lock);
dp->dl_stid.sc_file = fp; dp->dl_stid.sc_file = fp;
if (!fp->fi_lease) { if (!fp->fi_deleg_file) {
spin_unlock(&fp->fi_lock); spin_unlock(&fp->fi_lock);
spin_unlock(&state_lock); spin_unlock(&state_lock);
status = nfs4_setlease(dp); status = nfs4_setlease(dp);
@ -4929,9 +4929,25 @@ nfs4_transform_lock_offset(struct file_lock *lock)
lock->fl_end = OFFSET_MAX; lock->fl_end = OFFSET_MAX;
} }
/* Hack!: For now, we're defining this just so we can use a pointer to it static void nfsd4_fl_get_owner(struct file_lock *dst, struct file_lock *src)
* as a unique cookie to identify our (NFSv4's) posix locks. */ {
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 = { 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 static inline void
@ -4977,10 +4993,8 @@ find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner,
so_strhash) { so_strhash) {
if (so->so_is_open_owner) if (so->so_is_open_owner)
continue; continue;
if (!same_owner_str(so, owner)) if (same_owner_str(so, owner))
continue; return lockowner(nfs4_get_stateowner(so));
atomic_inc(&so->so_count);
return lockowner(so);
} }
return NULL; 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); atomic_inc(&stp->st_stid.sc_count);
stp->st_stid.sc_type = NFS4_LOCK_STID; stp->st_stid.sc_type = NFS4_LOCK_STID;
stp->st_stateowner = &lo->lo_owner; stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
atomic_inc(&lo->lo_owner.so_count);
get_nfs4_file(fp); get_nfs4_file(fp);
stp->st_stid.sc_file = fp; stp->st_stid.sc_file = fp;
stp->st_stid.sc_free = nfs4_free_lock_stateid; 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; status = nfserr_openmode;
goto out; 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_pid = current->tgid;
file_lock->fl_file = filp; file_lock->fl_file = filp;
file_lock->fl_flags = FL_POSIX; 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_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_pid = current->tgid;
file_lock->fl_file = filp; file_lock->fl_file = filp;
file_lock->fl_flags = FL_POSIX; 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; break;
} }
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);

View file

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

View file

@ -346,13 +346,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
goto out; goto out;
} }
error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); __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;
}
error = attach_dn(dn, dn_mark, id, fd, filp, mask); 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 */ /* !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 #define FILE_LOCK_DEFERRED 1
/* /* legacy typedef, should eventually be removed */
* 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.
*/
typedef void *fl_owner_t; typedef void *fl_owner_t;
struct file_lock_operations { struct file_lock_operations {
@ -868,10 +862,13 @@ struct file_lock_operations {
struct lock_manager_operations { struct lock_manager_operations {
int (*lm_compare_owner)(struct file_lock *, struct file_lock *); int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
unsigned long (*lm_owner_key)(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 */ void (*lm_notify)(struct file_lock *); /* unblock callback */
int (*lm_grant)(struct file_lock *, struct file_lock *, int); int (*lm_grant)(struct file_lock *, int);
void (*lm_break)(struct file_lock *); bool (*lm_break)(struct file_lock *);
int (*lm_change)(struct file_lock **, int); int (*lm_change)(struct file_lock **, int, struct list_head *);
void (*lm_setup)(struct file_lock *, void **);
}; };
struct lock_manager { struct lock_manager {
@ -966,7 +963,7 @@ void locks_free_lock(struct file_lock *fl);
extern void locks_init_lock(struct file_lock *); extern void locks_init_lock(struct file_lock *);
extern struct file_lock * locks_alloc_lock(void); 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 *, 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_posix(struct file *, fl_owner_t);
extern void locks_remove_file(struct file *); extern void locks_remove_file(struct file *);
extern void locks_release_private(struct file_lock *); 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 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 int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
extern void lease_get_mtime(struct inode *, struct timespec *time); extern void lease_get_mtime(struct inode *, struct timespec *time);
extern int generic_setlease(struct file *, long, struct file_lock **); extern int generic_setlease(struct file *, long, struct file_lock **, void **priv);
extern int vfs_setlease(struct file *, long, struct file_lock **); extern int vfs_setlease(struct file *, long, struct file_lock **, void **);
extern int lease_modify(struct file_lock **, int); extern int lease_modify(struct file_lock **, int, struct list_head *);
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);
#else /* !CONFIG_FILE_LOCKING */ #else /* !CONFIG_FILE_LOCKING */
static inline int fcntl_getlk(struct file *file, unsigned int cmd, static inline int fcntl_getlk(struct file *file, unsigned int cmd,
struct flock __user *user) struct flock __user *user)
@ -1013,12 +1008,12 @@ static inline int fcntl_setlk64(unsigned int fd, struct file *file,
#endif #endif
static inline int fcntl_setlease(unsigned int fd, struct file *filp, long arg) 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) static inline int fcntl_getlease(struct file *filp)
{ {
return 0; return F_UNLCK;
} }
static inline void locks_init_lock(struct file_lock *fl) 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; 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; 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, static inline int generic_setlease(struct file *filp, long arg,
struct file_lock **flp) struct file_lock **flp, void **priv)
{ {
return -EINVAL; return -EINVAL;
} }
static inline int vfs_setlease(struct file *filp, long arg, static inline int vfs_setlease(struct file *filp, long arg,
struct file_lock **lease) struct file_lock **lease, void **priv)
{ {
return -EINVAL; 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; 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 */ #endif /* !CONFIG_FILE_LOCKING */
@ -1151,8 +1135,8 @@ extern void fasync_free(struct fasync_struct *);
/* can be called from interrupts */ /* can be called from interrupts */
extern void kill_fasync(struct fasync_struct **, int, int); extern void kill_fasync(struct fasync_struct **, int, int);
extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force); extern void __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, unsigned long arg, int force);
extern void f_delown(struct file *filp); extern void f_delown(struct file *filp);
extern pid_t f_getown(struct file *filp); extern pid_t f_getown(struct file *filp);
extern int send_sigurg(struct fown_struct *fown); extern int send_sigurg(struct fown_struct *fown);
@ -1506,7 +1490,7 @@ struct file_operations {
int (*flock) (struct file *, int, struct file_lock *); 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_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); 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, long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len); loff_t len);
int (*show_fdinfo)(struct seq_file *m, struct file *f); 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); struct page *page, void *fsdata);
extern int always_delete_dentry(const struct dentry *); extern int always_delete_dentry(const struct dentry *);
extern struct inode *alloc_anon_inode(struct super_block *); 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 const struct dentry_operations simple_dentry_operations;
extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags); 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 */ unsigned char b_granted; /* VFS granted lock */
struct nlm_file * b_file; /* file in question */ struct nlm_file * b_file; /* file in question */
struct cache_req * b_cache_req; /* deferred request handling */ struct cache_req * b_cache_req; /* deferred request handling */
struct file_lock * b_fl; /* set for GETLK */
struct cache_deferred_req * b_deferred_req; struct cache_deferred_req * b_deferred_req;
unsigned int b_flags; /* block flags */ unsigned int b_flags; /* block flags */
#define B_QUEUED 1 /* lock queued */ #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_lock) (struct file *file, unsigned int cmd);
int (*file_fcntl) (struct file *file, unsigned int cmd, int (*file_fcntl) (struct file *file, unsigned int cmd,
unsigned long arg); 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, int (*file_send_sigiotask) (struct task_struct *tsk,
struct fown_struct *fown, int sig); struct fown_struct *fown, int sig);
int (*file_receive) (struct file *file); 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); unsigned long prot);
int security_file_lock(struct file *file, unsigned int cmd); 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_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, int security_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int sig); struct fown_struct *fown, int sig);
int security_file_receive(struct file *file); 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; 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, 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( TP_fast_assign(
__entry->fl = fl; __entry->fl = fl ? fl : NULL;
__entry->s_dev = inode->i_sb->s_dev; __entry->s_dev = inode->i_sb->s_dev;
__entry->i_ino = inode->i_ino; __entry->i_ino = inode->i_ino;
__entry->fl_next = fl->fl_next; __entry->fl_next = fl ? fl->fl_next : NULL;
__entry->fl_owner = fl->fl_owner; __entry->fl_owner = fl ? fl->fl_owner : NULL;
__entry->fl_flags = fl->fl_flags; __entry->fl_flags = fl ? fl->fl_flags : 0;
__entry->fl_type = fl->fl_type; __entry->fl_type = fl ? fl->fl_type : 0;
__entry->fl_break_time = fl->fl_break_time; __entry->fl_break_time = fl ? fl->fl_break_time : 0;
__entry->fl_downgrade_time = fl->fl_downgrade_time; __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", 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; err = -EFAULT;
if (get_user(pid, (int __user *)argp)) if (get_user(pid, (int __user *)argp))
break; break;
err = f_setown(sock->file, pid, 1); f_setown(sock->file, pid, 1);
err = 0;
break; break;
case FIOGETOWN: case FIOGETOWN:
case SIOCGPGRP: case SIOCGPGRP:

View file

@ -343,9 +343,9 @@ static int cap_file_fcntl(struct file *file, unsigned int cmd,
return 0; 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, 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); 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, 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; 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; struct file_security_struct *fsec;
fsec = file->f_security; fsec = file->f_security;
fsec->fown_sid = current_sid(); fsec->fown_sid = current_sid();
return 0;
} }
static int selinux_file_send_sigiotask(struct task_struct *tsk, 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 * Returns 0
* Further research may be required on this one. * 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(); struct smack_known *skp = smk_of_current();
file->f_security = skp->smk_known; file->f_security = skp->smk_known;
return 0;
} }
/** /**