mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-08 14:23:19 +00:00
ceph: keep auth cap when inode has flocks or posix locks
file locks are tracked by inode's auth mds. dropping auth caps is equivalent to releasing all file locks. Signed-off-by: "Yan, Zheng" <zyan@redhat.com> Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
parent
bebc6082da
commit
89aa593010
@ -493,6 +493,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
|
|||||||
ci->i_wb_ref = 0;
|
ci->i_wb_ref = 0;
|
||||||
ci->i_wrbuffer_ref = 0;
|
ci->i_wrbuffer_ref = 0;
|
||||||
ci->i_wrbuffer_ref_head = 0;
|
ci->i_wrbuffer_ref_head = 0;
|
||||||
|
atomic_set(&ci->i_filelock_ref, 0);
|
||||||
ci->i_shared_gen = 0;
|
ci->i_shared_gen = 0;
|
||||||
ci->i_rdcache_gen = 0;
|
ci->i_rdcache_gen = 0;
|
||||||
ci->i_rdcache_revoking = 0;
|
ci->i_rdcache_revoking = 0;
|
||||||
|
@ -30,19 +30,46 @@ void __init ceph_flock_init(void)
|
|||||||
get_random_bytes(&lock_secret, sizeof(lock_secret));
|
get_random_bytes(&lock_secret, sizeof(lock_secret));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
|
||||||
|
{
|
||||||
|
struct inode *inode = file_inode(src->fl_file);
|
||||||
|
atomic_inc(&ceph_inode(inode)->i_filelock_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ceph_fl_release_lock(struct file_lock *fl)
|
||||||
|
{
|
||||||
|
struct inode *inode = file_inode(fl->fl_file);
|
||||||
|
atomic_dec(&ceph_inode(inode)->i_filelock_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_lock_operations ceph_fl_lock_ops = {
|
||||||
|
.fl_copy_lock = ceph_fl_copy_lock,
|
||||||
|
.fl_release_private = ceph_fl_release_lock,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement fcntl and flock locking functions.
|
* Implement fcntl and flock locking functions.
|
||||||
*/
|
*/
|
||||||
static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
|
static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode,
|
||||||
int cmd, u8 wait, struct file_lock *fl)
|
int cmd, u8 wait, struct file_lock *fl)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
|
||||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
|
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||||
struct ceph_mds_request *req;
|
struct ceph_mds_request *req;
|
||||||
int err;
|
int err;
|
||||||
u64 length = 0;
|
u64 length = 0;
|
||||||
u64 owner;
|
u64 owner;
|
||||||
|
|
||||||
|
if (operation == CEPH_MDS_OP_SETFILELOCK) {
|
||||||
|
/*
|
||||||
|
* increasing i_filelock_ref closes race window between
|
||||||
|
* handling request reply and adding file_lock struct to
|
||||||
|
* inode. Otherwise, auth caps may get trimmed in the
|
||||||
|
* window. Caller function will decrease the counter.
|
||||||
|
*/
|
||||||
|
fl->fl_ops = &ceph_fl_lock_ops;
|
||||||
|
atomic_inc(&ceph_inode(inode)->i_filelock_ref);
|
||||||
|
}
|
||||||
|
|
||||||
if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK)
|
if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK)
|
||||||
wait = 0;
|
wait = 0;
|
||||||
|
|
||||||
@ -180,10 +207,11 @@ static int ceph_lock_wait_for_completion(struct ceph_mds_client *mdsc,
|
|||||||
*/
|
*/
|
||||||
int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
|
int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
|
||||||
{
|
{
|
||||||
u8 lock_cmd;
|
struct inode *inode = file_inode(file);
|
||||||
int err;
|
int err;
|
||||||
u8 wait = 0;
|
|
||||||
u16 op = CEPH_MDS_OP_SETFILELOCK;
|
u16 op = CEPH_MDS_OP_SETFILELOCK;
|
||||||
|
u8 lock_cmd;
|
||||||
|
u8 wait = 0;
|
||||||
|
|
||||||
if (!(fl->fl_flags & FL_POSIX))
|
if (!(fl->fl_flags & FL_POSIX))
|
||||||
return -ENOLCK;
|
return -ENOLCK;
|
||||||
@ -199,6 +227,17 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
|
|||||||
else if (IS_SETLKW(cmd))
|
else if (IS_SETLKW(cmd))
|
||||||
wait = 1;
|
wait = 1;
|
||||||
|
|
||||||
|
if (op == CEPH_MDS_OP_SETFILELOCK) {
|
||||||
|
/*
|
||||||
|
* increasing i_filelock_ref closes race window between
|
||||||
|
* handling request reply and adding file_lock struct to
|
||||||
|
* inode. Otherwise, i_auth_cap may get trimmed in the
|
||||||
|
* window. Caller function will decrease the counter.
|
||||||
|
*/
|
||||||
|
fl->fl_ops = &ceph_fl_lock_ops;
|
||||||
|
atomic_inc(&ceph_inode(inode)->i_filelock_ref);
|
||||||
|
}
|
||||||
|
|
||||||
if (F_RDLCK == fl->fl_type)
|
if (F_RDLCK == fl->fl_type)
|
||||||
lock_cmd = CEPH_LOCK_SHARED;
|
lock_cmd = CEPH_LOCK_SHARED;
|
||||||
else if (F_WRLCK == fl->fl_type)
|
else if (F_WRLCK == fl->fl_type)
|
||||||
@ -206,7 +245,7 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
|
|||||||
else
|
else
|
||||||
lock_cmd = CEPH_LOCK_UNLOCK;
|
lock_cmd = CEPH_LOCK_UNLOCK;
|
||||||
|
|
||||||
err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl);
|
err = ceph_lock_message(CEPH_LOCK_FCNTL, op, inode, lock_cmd, wait, fl);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (op != CEPH_MDS_OP_GETFILELOCK) {
|
if (op != CEPH_MDS_OP_GETFILELOCK) {
|
||||||
dout("mds locked, locking locally");
|
dout("mds locked, locking locally");
|
||||||
@ -215,7 +254,7 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
|
|||||||
/* undo! This should only happen if
|
/* undo! This should only happen if
|
||||||
* the kernel detects local
|
* the kernel detects local
|
||||||
* deadlock. */
|
* deadlock. */
|
||||||
ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
|
ceph_lock_message(CEPH_LOCK_FCNTL, op, inode,
|
||||||
CEPH_LOCK_UNLOCK, 0, fl);
|
CEPH_LOCK_UNLOCK, 0, fl);
|
||||||
dout("got %d on posix_lock_file, undid lock",
|
dout("got %d on posix_lock_file, undid lock",
|
||||||
err);
|
err);
|
||||||
@ -227,8 +266,9 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
|
|||||||
|
|
||||||
int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
|
int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
|
||||||
{
|
{
|
||||||
u8 lock_cmd;
|
struct inode *inode = file_inode(file);
|
||||||
int err;
|
int err;
|
||||||
|
u8 lock_cmd;
|
||||||
u8 wait = 0;
|
u8 wait = 0;
|
||||||
|
|
||||||
if (!(fl->fl_flags & FL_FLOCK))
|
if (!(fl->fl_flags & FL_FLOCK))
|
||||||
@ -239,6 +279,10 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
|
|||||||
|
|
||||||
dout("ceph_flock, fl_file: %p", fl->fl_file);
|
dout("ceph_flock, fl_file: %p", fl->fl_file);
|
||||||
|
|
||||||
|
/* see comment in ceph_lock */
|
||||||
|
fl->fl_ops = &ceph_fl_lock_ops;
|
||||||
|
atomic_inc(&ceph_inode(inode)->i_filelock_ref);
|
||||||
|
|
||||||
if (IS_SETLKW(cmd))
|
if (IS_SETLKW(cmd))
|
||||||
wait = 1;
|
wait = 1;
|
||||||
|
|
||||||
@ -250,13 +294,13 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
|
|||||||
lock_cmd = CEPH_LOCK_UNLOCK;
|
lock_cmd = CEPH_LOCK_UNLOCK;
|
||||||
|
|
||||||
err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
|
err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
|
||||||
file, lock_cmd, wait, fl);
|
inode, lock_cmd, wait, fl);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
err = locks_lock_file_wait(file, fl);
|
err = locks_lock_file_wait(file, fl);
|
||||||
if (err) {
|
if (err) {
|
||||||
ceph_lock_message(CEPH_LOCK_FLOCK,
|
ceph_lock_message(CEPH_LOCK_FLOCK,
|
||||||
CEPH_MDS_OP_SETFILELOCK,
|
CEPH_MDS_OP_SETFILELOCK,
|
||||||
file, CEPH_LOCK_UNLOCK, 0, fl);
|
inode, CEPH_LOCK_UNLOCK, 0, fl);
|
||||||
dout("got %d on locks_lock_file_wait, undid lock", err);
|
dout("got %d on locks_lock_file_wait, undid lock", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1462,6 +1462,11 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
|
|||||||
goto out;
|
goto out;
|
||||||
if ((used | wanted) & CEPH_CAP_ANY_WR)
|
if ((used | wanted) & CEPH_CAP_ANY_WR)
|
||||||
goto out;
|
goto out;
|
||||||
|
/* Note: it's possible that i_filelock_ref becomes non-zero
|
||||||
|
* after dropping auth caps. It doesn't hurt because reply
|
||||||
|
* of lock mds request will re-add auth caps. */
|
||||||
|
if (atomic_read(&ci->i_filelock_ref) > 0)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
/* The inode has cached pages, but it's no longer used.
|
/* The inode has cached pages, but it's no longer used.
|
||||||
* we can safely drop it */
|
* we can safely drop it */
|
||||||
|
@ -352,6 +352,7 @@ struct ceph_inode_info {
|
|||||||
int i_pin_ref;
|
int i_pin_ref;
|
||||||
int i_rd_ref, i_rdcache_ref, i_wr_ref, i_wb_ref;
|
int i_rd_ref, i_rdcache_ref, i_wr_ref, i_wb_ref;
|
||||||
int i_wrbuffer_ref, i_wrbuffer_ref_head;
|
int i_wrbuffer_ref, i_wrbuffer_ref_head;
|
||||||
|
atomic_t i_filelock_ref;
|
||||||
u32 i_shared_gen; /* increment each time we get FILE_SHARED */
|
u32 i_shared_gen; /* increment each time we get FILE_SHARED */
|
||||||
u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */
|
u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */
|
||||||
u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */
|
u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */
|
||||||
|
Loading…
Reference in New Issue
Block a user