ceph: fix file lock interruption
When a lock operation is interrupted, current code sends a unlock request to MDS to undo the lock operation. This method does not work as expected because the unlock request can drop locks that have already been acquired. The fix is use the newly introduced CEPH_LOCK_FCNTL_INTR/CEPH_LOCK_FLOCK_INTR requests to interrupt blocked file lock request. These requests do not drop locks that have alread been acquired, they only interrupt blocked file lock request. Signed-off-by: Yan, Zheng <zyan@redhat.com>
This commit is contained in:
parent
b2776bf714
commit
9280be24dc
4 changed files with 67 additions and 12 deletions
|
@ -9,6 +9,8 @@
|
|||
#include <linux/ceph/pagelist.h>
|
||||
|
||||
static u64 lock_secret;
|
||||
static int ceph_lock_wait_for_completion(struct ceph_mds_client *mdsc,
|
||||
struct ceph_mds_request *req);
|
||||
|
||||
static inline u64 secure_addr(void *addr)
|
||||
{
|
||||
|
@ -40,6 +42,9 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
|
|||
u64 length = 0;
|
||||
u64 owner;
|
||||
|
||||
if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK)
|
||||
wait = 0;
|
||||
|
||||
req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS);
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
|
@ -68,6 +73,9 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
|
|||
req->r_args.filelock_change.length = cpu_to_le64(length);
|
||||
req->r_args.filelock_change.wait = wait;
|
||||
|
||||
if (wait)
|
||||
req->r_wait_for_completion = ceph_lock_wait_for_completion;
|
||||
|
||||
err = ceph_mdsc_do_request(mdsc, inode, req);
|
||||
|
||||
if (operation == CEPH_MDS_OP_GETFILELOCK) {
|
||||
|
@ -96,6 +104,52 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ceph_lock_wait_for_completion(struct ceph_mds_client *mdsc,
|
||||
struct ceph_mds_request *req)
|
||||
{
|
||||
struct ceph_mds_request *intr_req;
|
||||
struct inode *inode = req->r_inode;
|
||||
int err, lock_type;
|
||||
|
||||
BUG_ON(req->r_op != CEPH_MDS_OP_SETFILELOCK);
|
||||
if (req->r_args.filelock_change.rule == CEPH_LOCK_FCNTL)
|
||||
lock_type = CEPH_LOCK_FCNTL_INTR;
|
||||
else if (req->r_args.filelock_change.rule == CEPH_LOCK_FLOCK)
|
||||
lock_type = CEPH_LOCK_FLOCK_INTR;
|
||||
else
|
||||
BUG_ON(1);
|
||||
BUG_ON(req->r_args.filelock_change.type == CEPH_LOCK_UNLOCK);
|
||||
|
||||
err = wait_for_completion_interruptible(&req->r_completion);
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
dout("ceph_lock_wait_for_completion: request %llu was interrupted\n",
|
||||
req->r_tid);
|
||||
|
||||
intr_req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETFILELOCK,
|
||||
USE_AUTH_MDS);
|
||||
if (IS_ERR(intr_req))
|
||||
return PTR_ERR(intr_req);
|
||||
|
||||
intr_req->r_inode = inode;
|
||||
ihold(inode);
|
||||
intr_req->r_num_caps = 1;
|
||||
|
||||
intr_req->r_args.filelock_change = req->r_args.filelock_change;
|
||||
intr_req->r_args.filelock_change.rule = lock_type;
|
||||
intr_req->r_args.filelock_change.type = CEPH_LOCK_UNLOCK;
|
||||
|
||||
err = ceph_mdsc_do_request(mdsc, inode, intr_req);
|
||||
ceph_mdsc_put_request(intr_req);
|
||||
|
||||
if (err && err != -ERESTARTSYS)
|
||||
return err;
|
||||
|
||||
wait_for_completion(&req->r_completion);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to set an fcntl lock.
|
||||
* For now, this just goes away to the server. Later it may be more awesome.
|
||||
|
@ -143,11 +197,6 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
|
|||
err);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (err == -ERESTARTSYS) {
|
||||
dout("undoing lock\n");
|
||||
ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
|
||||
CEPH_LOCK_UNLOCK, 0, fl);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
@ -186,11 +235,6 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
|
|||
file, CEPH_LOCK_UNLOCK, 0, fl);
|
||||
dout("got %d on flock_lock_file_wait, undid lock", err);
|
||||
}
|
||||
} else if (err == -ERESTARTSYS) {
|
||||
dout("undoing lock\n");
|
||||
ceph_lock_message(CEPH_LOCK_FLOCK,
|
||||
CEPH_MDS_OP_SETFILELOCK,
|
||||
file, CEPH_LOCK_UNLOCK, 0, fl);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -2208,6 +2208,8 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
|
|||
&req->r_completion, req->r_timeout);
|
||||
if (err == 0)
|
||||
err = -EIO;
|
||||
} else if (req->r_wait_for_completion) {
|
||||
err = req->r_wait_for_completion(mdsc, req);
|
||||
} else {
|
||||
err = wait_for_completion_killable(&req->r_completion);
|
||||
}
|
||||
|
|
|
@ -166,6 +166,11 @@ struct ceph_mds_client;
|
|||
*/
|
||||
typedef void (*ceph_mds_request_callback_t) (struct ceph_mds_client *mdsc,
|
||||
struct ceph_mds_request *req);
|
||||
/*
|
||||
* wait for request completion callback
|
||||
*/
|
||||
typedef int (*ceph_mds_request_wait_callback_t) (struct ceph_mds_client *mdsc,
|
||||
struct ceph_mds_request *req);
|
||||
|
||||
/*
|
||||
* an in-flight mds request
|
||||
|
@ -239,6 +244,7 @@ struct ceph_mds_request {
|
|||
struct completion r_completion;
|
||||
struct completion r_safe_completion;
|
||||
ceph_mds_request_callback_t r_callback;
|
||||
ceph_mds_request_wait_callback_t r_wait_for_completion;
|
||||
struct list_head r_unsafe_item; /* per-session unsafe list item */
|
||||
bool r_got_unsafe, r_got_safe, r_got_result;
|
||||
|
||||
|
|
|
@ -522,8 +522,11 @@ struct ceph_mds_reply_dirfrag {
|
|||
__le32 dist[];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_LOCK_FCNTL 1
|
||||
#define CEPH_LOCK_FLOCK 2
|
||||
#define CEPH_LOCK_FCNTL 1
|
||||
#define CEPH_LOCK_FLOCK 2
|
||||
#define CEPH_LOCK_FCNTL_INTR 3
|
||||
#define CEPH_LOCK_FLOCK_INTR 4
|
||||
|
||||
|
||||
#define CEPH_LOCK_SHARED 1
|
||||
#define CEPH_LOCK_EXCL 2
|
||||
|
|
Loading…
Reference in a new issue