From 2fad86e2f1e2ab85e6984ab0a8db8b3c35878a57 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Fri, 17 Apr 2015 20:27:56 +0800 Subject: [PATCH] client: flush dirty snap data before allowing new writes this guarantees that new writes do not overwrite existing dirty snap data. Signed-off-by: Yan, Zheng --- src/client/Client.cc | 113 ++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 44 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 6708304c015b6..833ad0acadb4e 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -2624,6 +2624,31 @@ void Client::unlink(Dentry *dn, bool keepdir, bool keepdentry) } } +/** + * For asynchronous flushes, check for errors from the IO and + * update the inode if necessary + */ +class C_Client_FlushComplete : public Context { +private: + Client *client; + Inode *inode; +public: + C_Client_FlushComplete(Client *c, Inode *in) : client(c), inode(in) { + inode->get(); + } + void finish(int r) { + assert(client->client_lock.is_locked_by_me()); + if (r != 0) { + client_t const whoami = client->whoami; // For the benefit of ldout prefix + ldout(client->cct, 1) << "I/O error from flush on inode " << inode + << " 0x" << std::hex << inode->ino << std::dec + << ": " << r << "(" << cpp_strerror(r) << ")" << dendl; + inode->async_err = r; + } + client->put_inode(inode); + } +}; + /**** * caps @@ -2693,22 +2718,46 @@ int Client::get_caps(Inode *in, int need, int want, int *phave, loff_t endoff) if (!in->is_any_caps()) return -ESTALE; - if (endoff > 0 && - (endoff >= (loff_t)in->max_size || - endoff > (loff_t)(in->size << 1)) && - endoff > (loff_t)in->wanted_max_size) { - ldout(cct, 10) << "wanted_max_size " << in->wanted_max_size << " -> " << endoff << dendl; - in->wanted_max_size = endoff; - check_caps(in, false); + int implemented; + int have = in->caps_issued(&implemented); + + bool waitfor_caps = false; + bool waitfor_commit = false; + + if (have & need & CEPH_CAP_FILE_WR) { + if (endoff > 0 && + (endoff >= (loff_t)in->max_size || + endoff > (loff_t)(in->size << 1)) && + endoff > (loff_t)in->wanted_max_size) { + ldout(cct, 10) << "wanted_max_size " << in->wanted_max_size << " -> " << endoff << dendl; + in->wanted_max_size = endoff; + check_caps(in, false); + } + + if (endoff >= 0 && endoff > (loff_t)in->max_size) { + ldout(cct, 10) << "waiting on max_size, endoff " << endoff << " max_size " << in->max_size << " on " << *in << dendl; + waitfor_caps = true; + } + if (!in->cap_snaps.empty()) { + if (in->cap_snaps.rbegin()->second->writing) { + ldout(cct, 10) << "waiting on cap_snap write to complete" << dendl; + waitfor_caps = true; + } + for (map::iterator p = in->cap_snaps.begin(); + p != in->cap_snaps.end(); + ++p) + if (p->second->dirty_data) { + waitfor_commit = true; + break; + } + if (waitfor_commit) { + _flush(in, new C_Client_FlushComplete(this, in)); + ldout(cct, 10) << "waiting for WRBUFFER to get dropped" << dendl; + } + } } - if (endoff >= 0 && endoff > (loff_t)in->max_size) { - ldout(cct, 10) << "waiting on max_size, endoff " << endoff << " max_size " << in->max_size << " on " << *in << dendl; - } else if (!in->cap_snaps.empty() && in->cap_snaps.rbegin()->second->writing) { - ldout(cct, 10) << "waiting on cap_snap write to complete" << dendl; - } else { - int implemented; - int have = in->caps_issued(&implemented); + if (!waitfor_caps && !waitfor_commit) { if ((have & need) == need) { int butnot = want & ~(have & need); int revoking = implemented & ~have; @@ -2723,13 +2772,17 @@ int Client::get_caps(Inode *in, int need, int want, int *phave, loff_t endoff) } } ldout(cct, 10) << "waiting for caps need " << ccap_string(need) << " want " << ccap_string(want) << dendl; + waitfor_caps = true; } if ((need & CEPH_CAP_FILE_WR) && in->auth_cap && in->auth_cap->session->readonly) return -EROFS; - - wait_on_list(in->waitfor_caps); + + if (waitfor_caps) + wait_on_list(in->waitfor_caps); + else if (waitfor_commit) + wait_on_list(in->waitfor_commit); } } @@ -4258,34 +4311,6 @@ void Client::_try_to_trim_inode(Inode *in) } } -/** - * For asynchronous flushes, check for errors from the IO and - * update the inode if necessary - */ -class C_Client_FlushComplete : public Context { - private: - Client *client; - Inode *inode; - - public: - C_Client_FlushComplete(Client *c, Inode *in) : client(c), inode(in) - { - inode->get(); - } - - void finish(int r) { - assert(client->client_lock.is_locked_by_me()); - if (r != 0) { - client_t const whoami = client->whoami; // For the benefit of ldout prefix - ldout(client->cct, 1) << "I/O error from flush on inode " << inode - << " 0x" << std::hex << inode->ino << std::dec - << ": " << r << "(" << cpp_strerror(r) << ")" << dendl; - inode->async_err = r; - } - client->put_inode(inode); - } -}; - void Client::handle_cap_grant(MetaSession *session, Inode *in, Cap *cap, MClientCaps *m) { mds_rank_t mds = session->mds_num; -- 2.39.5