Commit 9280be24 authored by Yan, Zheng's avatar Yan, Zheng Committed by Ilya Dryomov

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: default avatarYan, Zheng <zyan@redhat.com>
parent b2776bf7
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <linux/ceph/pagelist.h> #include <linux/ceph/pagelist.h>
static u64 lock_secret; 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) static inline u64 secure_addr(void *addr)
{ {
...@@ -40,6 +42,9 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, ...@@ -40,6 +42,9 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
u64 length = 0; u64 length = 0;
u64 owner; u64 owner;
if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK)
wait = 0;
req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS); req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS);
if (IS_ERR(req)) if (IS_ERR(req))
return PTR_ERR(req); return PTR_ERR(req);
...@@ -68,6 +73,9 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, ...@@ -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.length = cpu_to_le64(length);
req->r_args.filelock_change.wait = wait; 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); err = ceph_mdsc_do_request(mdsc, inode, req);
if (operation == CEPH_MDS_OP_GETFILELOCK) { if (operation == CEPH_MDS_OP_GETFILELOCK) {
...@@ -96,6 +104,52 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, ...@@ -96,6 +104,52 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
return err; 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. * Attempt to set an fcntl lock.
* For now, this just goes away to the server. Later it may be more awesome. * 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) ...@@ -143,11 +197,6 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
err); err);
} }
} }
} else if (err == -ERESTARTSYS) {
dout("undoing lock\n");
ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
CEPH_LOCK_UNLOCK, 0, fl);
} }
return err; return err;
} }
...@@ -186,11 +235,6 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) ...@@ -186,11 +235,6 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
file, CEPH_LOCK_UNLOCK, 0, fl); file, CEPH_LOCK_UNLOCK, 0, fl);
dout("got %d on flock_lock_file_wait, undid lock", err); 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; return err;
} }
......
...@@ -2208,6 +2208,8 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc, ...@@ -2208,6 +2208,8 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
&req->r_completion, req->r_timeout); &req->r_completion, req->r_timeout);
if (err == 0) if (err == 0)
err = -EIO; err = -EIO;
} else if (req->r_wait_for_completion) {
err = req->r_wait_for_completion(mdsc, req);
} else { } else {
err = wait_for_completion_killable(&req->r_completion); err = wait_for_completion_killable(&req->r_completion);
} }
......
...@@ -166,6 +166,11 @@ struct ceph_mds_client; ...@@ -166,6 +166,11 @@ struct ceph_mds_client;
*/ */
typedef void (*ceph_mds_request_callback_t) (struct ceph_mds_client *mdsc, typedef void (*ceph_mds_request_callback_t) (struct ceph_mds_client *mdsc,
struct ceph_mds_request *req); 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 * an in-flight mds request
...@@ -239,6 +244,7 @@ struct ceph_mds_request { ...@@ -239,6 +244,7 @@ struct ceph_mds_request {
struct completion r_completion; struct completion r_completion;
struct completion r_safe_completion; struct completion r_safe_completion;
ceph_mds_request_callback_t r_callback; 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 */ struct list_head r_unsafe_item; /* per-session unsafe list item */
bool r_got_unsafe, r_got_safe, r_got_result; bool r_got_unsafe, r_got_safe, r_got_result;
......
...@@ -522,8 +522,11 @@ struct ceph_mds_reply_dirfrag { ...@@ -522,8 +522,11 @@ struct ceph_mds_reply_dirfrag {
__le32 dist[]; __le32 dist[];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define CEPH_LOCK_FCNTL 1 #define CEPH_LOCK_FCNTL 1
#define CEPH_LOCK_FLOCK 2 #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_SHARED 1
#define CEPH_LOCK_EXCL 2 #define CEPH_LOCK_EXCL 2
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment