forked from Minki/linux
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:
commit
ef4a48c513
@ -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 *);
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 "
|
||||
|
21
fs/fcntl.c
21
fs/fcntl.c
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
18
fs/libfs.c
18
fs/libfs.c
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
444
fs/locks.c
444
fs/locks.c
@ -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))
|
||||
goto restart;
|
||||
}
|
||||
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;
|
||||
if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK))
|
||||
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;
|
||||
goto out;
|
||||
lease = *my_before;
|
||||
error = lease->fl_lmops->lm_change(my_before, arg, &dispose);
|
||||
if (error)
|
||||
goto out;
|
||||
goto out_setup;
|
||||
}
|
||||
|
||||
error = -EINVAL;
|
||||
@ -1619,43 +1667,61 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_setlease - sets a lease on an open file
|
||||
* @filp: file pointer
|
||||
* @arg: type of lease to obtain
|
||||
* @flp: input - file_lock to use, output - file_lock inserted
|
||||
* @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)
|
||||
/**
|
||||
* 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)
|
||||
return filp->f_op->setlease(filp, arg, lease);
|
||||
return filp->f_op->setlease(filp, arg, lease, priv);
|
||||
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
|
||||
*
|
||||
* 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;
|
||||
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;
|
||||
}
|
||||
@ -2206,7 +2229,8 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
|
||||
error = -EFAULT;
|
||||
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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user