From: Xiubo Li Date: Wed, 23 Sep 2020 01:06:05 +0000 (+0800) Subject: client: unlock client_lock when copying data to bufferlist X-Git-Tag: v17.0.0~1000^2~1 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=9d0e88c3ffbec01abffea6ac14f6d27b8a8c1556;p=ceph.git client: unlock client_lock when copying data to bufferlist It's no need to hold the lock when copying the data, which may take a long time. Fixes: https://tracker.ceph.com/issues/47047 Signed-off-by: Xiubo Li --- diff --git a/src/client/Client.cc b/src/client/Client.cc index 437ec878d577e..0263aa78e666e 100755 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -9659,24 +9659,16 @@ int Client::_read_sync(Fh *f, uint64_t off, uint64_t len, bufferlist *bl, ldout(cct, 10) << __func__ << " " << *in << " " << off << "~" << len << dendl; - while (left > 0) { - C_SaferCond onfinish("Client::_read_sync flock"); - bufferlist tbl; - - int wanted = left; - filer->read_trunc(in->ino, &in->layout, in->snapid, - pos, left, &tbl, 0, - in->truncate_size, in->truncate_seq, - &onfinish); - client_lock.unlock(); + // 0 success, 1 continue and < 0 error happen. + auto wait_and_copy = [&](C_SaferCond &onfinish, bufferlist &tbl, int wanted) { int r = onfinish.wait(); - client_lock.lock(); // if we get ENOENT from OSD, assume 0 bytes returned if (r == -ENOENT) r = 0; if (r < 0) return r; + if (tbl.length()) { r = tbl.length(); @@ -9699,12 +9691,31 @@ int Client::_read_sync(Fh *f, uint64_t off, uint64_t len, bufferlist *bl, pos += some; left -= some; if (left == 0) - return read; + return 0; } *checkeof = true; - return read; + return 0; } + return 1; + }; + + while (left > 0) { + C_SaferCond onfinish("Client::_read_sync flock"); + bufferlist tbl; + + int wanted = left; + filer->read_trunc(in->ino, &in->layout, in->snapid, + pos, left, &tbl, 0, + in->truncate_size, in->truncate_seq, + &onfinish); + client_lock.unlock(); + int r = wait_and_copy(onfinish, tbl, wanted); + client_lock.lock(); + if (!r) + return read; + if (r < 0) + return r; } return read; } @@ -9744,7 +9755,7 @@ int Client::pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) int64_t Client::_preadv_pwritev_locked(Fh *fh, const struct iovec *iov, unsigned iovcnt, int64_t offset, bool write, - bool clamp_to_int) + bool clamp_to_int, std::unique_lock &cl) { #if defined(__linux__) && defined(O_PATH) if (fh->flags & O_PATH) @@ -9774,18 +9785,20 @@ int64_t Client::_preadv_pwritev_locked(Fh *fh, const struct iovec *iov, if (r <= 0) return r; + cl.unlock(); auto iter = bl.cbegin(); for (unsigned j = 0, resid = r; j < iovcnt && resid > 0; j++) { /* - * This piece of code aims to handle the case that bufferlist does not have enough data - * to fill in the iov + * This piece of code aims to handle the case that bufferlist + * does not have enough data to fill in the iov */ const auto round_size = std::min(resid, iov[j].iov_len); iter.copy(round_size, reinterpret_cast(iov[j].iov_base)); resid -= round_size; /* iter is self-updating */ } - return r; + cl.lock(); + return r; } } @@ -9798,11 +9811,11 @@ int Client::_preadv_pwritev(int fd, const struct iovec *iov, unsigned iovcnt, in tout(cct) << fd << std::endl; tout(cct) << offset << std::endl; - std::scoped_lock lock(client_lock); + std::unique_lock cl(client_lock); Fh *fh = get_filehandle(fd); if (!fh) - return -EBADF; - return _preadv_pwritev_locked(fh, iov, iovcnt, offset, write, true); + return -EBADF; + return _preadv_pwritev_locked(fh, iov, iovcnt, offset, write, true, cl); } int64_t Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf, @@ -13833,8 +13846,8 @@ int64_t Client::ll_writev(struct Fh *fh, const struct iovec *iov, int iovcnt, in if (!mref_reader.is_state_satisfied()) return -ENOTCONN; - std::scoped_lock lock(client_lock); - return _preadv_pwritev_locked(fh, iov, iovcnt, off, true, false); + std::unique_lock cl(client_lock); + return _preadv_pwritev_locked(fh, iov, iovcnt, off, true, false, cl); } int64_t Client::ll_readv(struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off) @@ -13843,8 +13856,8 @@ int64_t Client::ll_readv(struct Fh *fh, const struct iovec *iov, int iovcnt, int if (!mref_reader.is_state_satisfied()) return -ENOTCONN; - std::scoped_lock lock(client_lock); - return _preadv_pwritev_locked(fh, iov, iovcnt, off, false, false); + std::unique_lock cl(client_lock); + return _preadv_pwritev_locked(fh, iov, iovcnt, off, false, false, cl); } int Client::ll_flush(Fh *fh) diff --git a/src/client/Client.h b/src/client/Client.h index 1405715545efa..73b287cddd9dc 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -1234,8 +1234,10 @@ private: int64_t _read(Fh *fh, int64_t offset, uint64_t size, bufferlist *bl); int64_t _write(Fh *fh, int64_t offset, uint64_t size, const char *buf, const struct iovec *iov, int iovcnt); - int64_t _preadv_pwritev_locked(Fh *f, const struct iovec *iov, - unsigned iovcnt, int64_t offset, bool write, bool clamp_to_int); + int64_t _preadv_pwritev_locked(Fh *fh, const struct iovec *iov, + unsigned iovcnt, int64_t offset, + bool write, bool clamp_to_int, + std::unique_lock &cl); int _preadv_pwritev(int fd, const struct iovec *iov, unsigned iovcnt, int64_t offset, bool write); int _flush(Fh *fh); int _fsync(Fh *fh, bool syncdataonly);