From: Yan, Zheng Date: Mon, 13 Oct 2014 02:44:46 +0000 (+0800) Subject: client: allow interrupting blocked file lock operation X-Git-Tag: v0.80.9~7^2~4 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ccbdf514717cb0e48d67b57197d6e538faeea415;p=ceph.git client: allow interrupting blocked file lock operation This commit introduce two new types of setfilelock request. Unlike setfilelock (UNLOCK) request, these two new types of setfilelock request do not drop locks that have alread been acquired, they only interrupt blocked setfilelock request. Signed-off-by: Yan, Zheng (cherry picked from commit 4134c149d3759dd6a3aaa1a353b77bbfe8e9491b) --- diff --git a/src/client/Client.cc b/src/client/Client.cc index 91262cfc3e3..26e6410aaf0 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -6868,7 +6868,7 @@ int Client::statfs(const char *path, struct statvfs *stbuf) } int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, - struct flock *fl, uint64_t owner) + struct flock *fl, uint64_t owner, void *fuse_req) { ldout(cct, 10) << "_do_filelock ino " << in->ino << (lock_type == CEPH_LOCK_FCNTL ? " fcntl" : " flock") @@ -6885,6 +6885,9 @@ int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, else return -EIO; + if (op != CEPH_MDS_OP_SETFILELOCK || lock_cmd == CEPH_LOCK_UNLOCK) + sleep = 0; + /* * Set the most significant bit, so that MDS knows the 'owner' * is sufficient to identify the owner of lock. (old code uses @@ -6906,8 +6909,21 @@ int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, req->head.args.filelock_change.length = fl->l_len; req->head.args.filelock_change.wait = sleep; + int ret; bufferlist bl; - int ret = make_request(req, -1, -1, NULL, NULL, -1, &bl); + + if (sleep && switch_interrupt_cb && fuse_req) { + // enable interrupt + switch_interrupt_cb(fuse_req, req->get()); + + ret = make_request(req, -1, -1, NULL, NULL, -1, &bl); + + // disable interrupt + switch_interrupt_cb(fuse_req, NULL); + put_request(req); + } else { + ret = make_request(req, -1, -1, NULL, NULL, -1, &bl); + } if (ret == 0) { if (op == CEPH_MDS_OP_GETFILELOCK) { @@ -6958,6 +6974,30 @@ int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, return ret; } +int Client::_interrupt_filelock(MetaRequest *req) +{ + Inode *in = req->inode(); + + int lock_type; + if (req->head.args.filelock_change.rule == CEPH_LOCK_FLOCK) + lock_type = CEPH_LOCK_FLOCK_INTR; + else if (req->head.args.filelock_change.rule == CEPH_LOCK_FCNTL) + lock_type = CEPH_LOCK_FCNTL_INTR; + else + assert(0); + + MetaRequest *intr_req = new MetaRequest(CEPH_MDS_OP_SETFILELOCK); + filepath path; + in->make_nosnap_relative_path(path); + intr_req->set_filepath(path); + intr_req->set_inode(in); + intr_req->head.args.filelock_change = req->head.args.filelock_change; + intr_req->head.args.filelock_change.rule = lock_type; + intr_req->head.args.filelock_change.type = CEPH_LOCK_UNLOCK; + + return make_request(intr_req, -1, -1, NULL, NULL, -1); +} + void Client::_encode_filelocks(Inode *in, bufferlist& bl) { if (!in->fcntl_locks && !in->flock_locks) @@ -7069,16 +7109,16 @@ int Client::_getlk(Fh *fh, struct flock *fl, uint64_t owner) return ret; } -int Client::_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep) +int Client::_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req) { Inode *in = fh->inode; ldout(cct, 10) << "_setlk " << fh << " ino " << in->ino << dendl; - int ret = _do_filelock(in, fh, CEPH_LOCK_FCNTL, CEPH_MDS_OP_SETFILELOCK, sleep, fl, owner); + int ret = _do_filelock(in, fh, CEPH_LOCK_FCNTL, CEPH_MDS_OP_SETFILELOCK, sleep, fl, owner, fuse_req); ldout(cct, 10) << "_setlk " << fh << " ino " << in->ino << " result=" << ret << dendl; return ret; } -int Client::_flock(Fh *fh, int cmd, uint64_t owner) +int Client::_flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req) { Inode *in = fh->inode; ldout(cct, 10) << "_flock " << fh << " ino " << in->ino << dendl; @@ -7106,7 +7146,7 @@ int Client::_flock(Fh *fh, int cmd, uint64_t owner) fl.l_type = type; fl.l_whence = SEEK_SET; - int ret = _do_filelock(in, fh, CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, sleep, &fl, owner); + int ret = _do_filelock(in, fh, CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, sleep, &fl, owner, fuse_req); ldout(cct, 10) << "_flock " << fh << " ino " << in->ino << " result=" << ret << dendl; return ret; } @@ -9012,28 +9052,36 @@ int Client::ll_getlk(Fh *fh, struct flock *fl, uint64_t owner) return _getlk(fh, fl, owner); } -int Client::ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep) +int Client::ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_setlk (fh) " << fh << " " << fh->inode->ino << dendl; tout(cct) << "ll_setk (fh)" << (unsigned long)fh << std::endl; - return _setlk(fh, fl, owner, sleep); + return _setlk(fh, fl, owner, sleep, fuse_req); } -int Client::ll_flock(Fh *fh, int cmd, uint64_t owner) +int Client::ll_flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_flock (fh) " << fh << " " << fh->inode->ino << dendl; tout(cct) << "ll_flock (fh)" << (unsigned long)fh << std::endl; - return _flock(fh, cmd, owner); + return _flock(fh, cmd, owner, fuse_req); } void Client::ll_interrupt(void *d) { + Mutex::Locker lock(client_lock); + + MetaRequest *req = static_cast(d); + ldout(cct, 3) << "ll_interrupt tid " << req->get_tid() << dendl; + tout(cct) << "ll_interrupt tid " << req->get_tid() << std::endl; + + assert(req->head.op == CEPH_MDS_OP_SETFILELOCK); + _interrupt_filelock(req); } // ========================================= diff --git a/src/client/Client.h b/src/client/Client.h index 6c3274e38cc..f102892b679 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -609,8 +609,8 @@ private: int _sync_fs(); int _fallocate(Fh *fh, int mode, int64_t offset, int64_t length); int _getlk(Fh *fh, struct flock *fl, uint64_t owner); - int _setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep); - int _flock(Fh *fh, int cmd, uint64_t owner); + int _setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req=NULL); + int _flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req=NULL); int get_or_create(Inode *dir, const char* name, Dentry **pdn, bool expect_null=false); @@ -621,7 +621,8 @@ private: inodeno_t _get_inodeno(Inode *in); int _do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, - struct flock *fl, uint64_t owner); + struct flock *fl, uint64_t owner, void *fuse_req=NULL); + int _interrupt_filelock(MetaRequest *req); void _encode_filelocks(Inode *in, bufferlist& bl); void _release_filelocks(Fh *fh); void _update_lock_state(struct flock *fl, uint64_t owner, ceph_lock_state_t *lock_state); @@ -831,8 +832,8 @@ public: int ll_fallocate(Fh *fh, int mode, loff_t offset, loff_t length); int ll_release(Fh *fh); int ll_getlk(Fh *fh, struct flock *fl, uint64_t owner); - int ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep); - int ll_flock(Fh *fh, int cmd, uint64_t owner); + int ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep, void *fuse_req); + int ll_flock(Fh *fh, int cmd, uint64_t owner, void *fuse_req); void ll_interrupt(void *d); int ll_get_stripe_osd(struct Inode *in, uint64_t blockno, ceph_file_layout* layout); diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index cccb64287e2..47339125623 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -662,7 +662,7 @@ static void fuse_ll_setlk(fuse_req_t req, fuse_ino_t ino, return; } - int r = cfuse->client->ll_setlk(fh, lock, fi->lock_owner, sleep); + int r = cfuse->client->ll_setlk(fh, lock, fi->lock_owner, sleep, req); fuse_reply_err(req, -r); } @@ -694,7 +694,7 @@ static void fuse_ll_flock(fuse_req_t req, fuse_ino_t ino, return; } - int r = cfuse->client->ll_flock(fh, cmd, fi->lock_owner); + int r = cfuse->client->ll_flock(fh, cmd, fi->lock_owner, req); fuse_reply_err(req, -r); } #endif diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index 10b52a5033a..d16df6272c2 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -505,8 +505,10 @@ 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 diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 3a96f931a26..80a0fba9b52 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -3085,13 +3085,20 @@ void Server::handle_client_file_setlock(MDRequestRef& mdr) dout(0) << "handle_client_file_setlock: " << set_lock << dendl; ceph_lock_state_t *lock_state = NULL; + bool interrupt = false; // get the appropriate lock state switch (req->head.args.filelock_change.rule) { + case CEPH_LOCK_FLOCK_INTR: + interrupt = true; + // fall-thru case CEPH_LOCK_FLOCK: lock_state = &cur->flock_locks; break; + case CEPH_LOCK_FCNTL_INTR: + interrupt = true; + // fall-thru case CEPH_LOCK_FCNTL: lock_state = &cur->fcntl_locks; break; @@ -3110,16 +3117,15 @@ void Server::handle_client_file_setlock(MDRequestRef& mdr) if (lock_state->is_waiting(set_lock)) { dout(10) << " unlock removing waiting lock " << set_lock << dendl; lock_state->remove_waiting(set_lock); - } else { + cur->take_waiting(CInode::WAIT_FLOCK, waiters); + } else if (!interrupt) { dout(10) << " unlock attempt on " << set_lock << dendl; lock_state->remove_lock(set_lock, activated_locks); cur->take_waiting(CInode::WAIT_FLOCK, waiters); } - reply_request(mdr, 0); - /* For now we're ignoring the activated locks because their responses - * will be sent when the lock comes up again in rotation by the MDS. - * It's a cheap hack, but it's easy to code. */ mds->queue_waiters(waiters); + + reply_request(mdr, 0); } else { dout(10) << " lock attempt on " << set_lock << dendl; if (mdr->more()->flock_was_waiting &&