Skip to content

Commit

Permalink
ceph: fix file lock interruption
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
ukernel authored and idryomov committed Dec 17, 2014
1 parent b2776bf commit 9280be2
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 12 deletions.
64 changes: 54 additions & 10 deletions fs/ceph/locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions fs/ceph/mds_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
6 changes: 6 additions & 0 deletions fs/ceph/mds_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down
7 changes: 5 additions & 2 deletions include/linux/ceph/ceph_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 9280be2

Please sign in to comment.