]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: allow clients to traverse dentries they xlock.
authorSage Weil <sage@newdream.net>
Mon, 12 Jan 2009 00:49:04 +0000 (16:49 -0800)
committerSage Weil <sage@newdream.net>
Mon, 12 Jan 2009 00:49:04 +0000 (16:49 -0800)
This could be cleaner.. maybe CDentry::get_inode() should take
a client argument?  Would need to fix up direct access to
dn->inode...

src/mds/CDentry.h
src/mds/CDir.cc
src/mds/CInode.cc
src/mds/MDCache.cc
src/mds/MDCache.h
src/mds/Server.cc
src/mds/Server.h

index 24d504d6a822c3e27c4c19f227330ffa10382be5..b81c6e3b9410a753c3c0cdb44718ec7610a2887e 100644 (file)
@@ -91,6 +91,7 @@ protected:
   unsigned char remote_d_type;
 
   CInode *inode; // linked inode (if any)
+  CInode *projected_inode;  // projected inode (if any)
   CDir *dir;     // containing dirfrag
 
   version_t version;  // dir version when last touched.
@@ -126,7 +127,7 @@ public:
     name(n),
     first(f), last(l),
     remote_ino(0), remote_d_type(0),
-    inode(0), dir(0),
+    inode(0), projected_inode(0), dir(0),
     version(0), projected_version(0),
     xlist_dirty(this),
     auth_pins(0), nested_auth_pins(0), nested_anchors(0),
@@ -136,7 +137,7 @@ public:
     name(n),
     first(f), last(l),
     remote_ino(ino), remote_d_type(dt),
-    inode(0), dir(0),
+    inode(0), projected_inode(0), dir(0),
     version(0), projected_version(0),
     xlist_dirty(this),
     auth_pins(0), nested_auth_pins(0), nested_anchors(0),
index a773e1b48157543d0cbdf1f2fd4aca78520419e3..5be844b4e6f527d09f1cadf9c3704a5293b7eec0 100644 (file)
@@ -388,6 +388,7 @@ void CDir::link_inode_work( CDentry *dn, CInode *in)
 {
   assert(dn->inode == 0);
   dn->inode = in;
+  dn->projected_inode = 0;
   in->set_primary_parent(dn);
 
   if (dn->last == CEPH_NOSNAP)
index 90516a84bfd0b88669bd2c6c491cc6a240391db9..18e3462e5416d40f1a9e8fe39dfce761fc3441c7 100644 (file)
@@ -1250,8 +1250,8 @@ SnapRealm *CInode::find_snaprealm()
   while (!cur->snaprealm) {
     if (cur->get_parent_dn())
       cur = cur->get_parent_dn()->get_dir()->get_inode();
-    else if (cur == this && get_projected_parent_dn())
-      cur = get_projected_parent_dn()->get_dir()->get_inode();
+    else if (get_projected_parent_dn())
+      cur = cur->get_projected_parent_dn()->get_dir()->get_inode();
     else
       break;
   }
index 91c4594d832fcca594d723ba25264ff4bd9666c0..9030a4fd5fe662ca4bcbc418195ca74bb00b0c75 100644 (file)
@@ -5170,7 +5170,8 @@ int MDCache::path_traverse(MDRequest *mdr, Message *req,     // who
                            vector<CDentry*>& trace,          // result
                           snapid_t *psnapid, CInode **psnapdiri,
                            bool follow_trailing_symlink,     // how
-                           int onfail)
+                           int onfail,
+                          bool allow_projected)
 {
   assert(mdr || req);
   bool null_okay = (onfail == MDS_TRAVERSE_DISCOVERXLOCK);
@@ -5184,6 +5185,8 @@ int MDCache::path_traverse(MDRequest *mdr, Message *req,     // who
   if (psnapdiri)
     *psnapdiri = 0;
 
+  int client = mdr->reqid.name.is_client() ? mdr->reqid.name.num() : -1;
+
   // root
   CInode *cur = get_inode(origpath.get_ino());
   if (cur == NULL) {
@@ -5307,6 +5310,15 @@ int MDCache::path_traverse(MDRequest *mdr, Message *req,     // who
     // dentry
     CDentry *dn = curdir->lookup(path[depth], snapid);
 
+    bool use_projected = false;
+    if (allow_projected &&
+       dn &&
+       dn->is_null() &&
+       dn->lock.is_xlocked() &&
+       dn->lock.can_rdlock(mdr, client) &&
+       dn->projected_inode)
+      use_projected = true;
+
     // null and last_bit and xlocked by me?
     if (dn && dn->is_null()) {
       if (null_okay) {
@@ -5314,7 +5326,9 @@ int MDCache::path_traverse(MDRequest *mdr, Message *req,     // who
        trace.push_back(dn);
        break; // done!
       }
-      if (dn->lock.is_xlocked() && dn->lock.get_xlocked_by() != mdr) {
+      if (dn->lock.is_xlocked() &&
+         dn->lock.get_xlocked_by() != mdr &&
+         !use_projected) {
         dout(10) << "traverse: xlocked null dentry at " << *dn << dendl;
         dn->lock.add_waiter(SimpleLock::WAIT_RD, _get_waiter(mdr, req));
        if (mds->logger) mds->logger->inc("tlock");
@@ -5323,20 +5337,25 @@ int MDCache::path_traverse(MDRequest *mdr, Message *req,     // who
 
     }
 
-    if (dn && !dn->is_null()) {
+    if (dn && (!dn->is_null() || use_projected)) {
       // dentry exists.  xlocked?
-      if (!noperm && dn->lock.is_xlocked() && dn->lock.get_xlocked_by() != mdr) {
+      if (!noperm &&
+         dn->lock.is_xlocked() &&
+         dn->lock.get_xlocked_by() != mdr &&
+         !dn->lock.can_rdlock(mdr, client)) {
         dout(10) << "traverse: xlocked dentry at " << *dn << dendl;
         dn->lock.add_waiter(SimpleLock::WAIT_RD, _get_waiter(mdr, req));
        if (mds->logger) mds->logger->inc("tlock");
         return 1;
       }
 
+      CInode *in = use_projected ? dn->projected_inode : dn->inode;
+      
       // do we have inode?
-      if (!dn->inode) {
+      if (!in) {
         assert(dn->is_remote());
         // do i have it?
-        CInode *in = get_inode(dn->get_remote_ino());
+        in = get_inode(dn->get_remote_ino());
         if (in) {
           dout(7) << "linking in remote in " << *in << dendl;
           dn->link_remote(in);
@@ -5350,11 +5369,11 @@ int MDCache::path_traverse(MDRequest *mdr, Message *req,     // who
       }
 
       // symlink?
-      if (dn->inode->is_symlink() &&
+      if (in->is_symlink() &&
           (follow_trailing_symlink || depth < path.depth()-1)) {
         // symlink, resolve!
-        filepath sym = dn->inode->symlink;
-        dout(10) << "traverse: hit symlink " << *dn->inode << " to " << sym << dendl;
+        filepath sym = in->symlink;
+        dout(10) << "traverse: hit symlink " << *in << " to " << sym << dendl;
 
         // break up path components
         // /head/symlink/tail
@@ -5363,18 +5382,18 @@ int MDCache::path_traverse(MDRequest *mdr, Message *req,     // who
         dout(10) << "traverse: path head = " << head << dendl;
         dout(10) << "traverse: path tail = " << tail << dendl;
         
-        if (symlinks_resolved.count(pair<CInode*,string>(dn->inode, tail.get_path()))) {
+        if (symlinks_resolved.count(pair<CInode*,string>(in, tail.get_path()))) {
           dout(10) << "already hit this symlink, bailing to avoid the loop" << dendl;
           return -ELOOP;
         }
-        symlinks_resolved.insert(pair<CInode*,string>(dn->inode, tail.get_path()));
+        symlinks_resolved.insert(pair<CInode*,string>(in, tail.get_path()));
 
         // start at root?
-        if (dn->inode->symlink[0] == '/') {
+        if (in->symlink[0] == '/') {
           // absolute
           trace.clear();
           depth = 0;
-         path = dn->inode->symlink;
+         path = in->symlink;
          path.append(tail);
           dout(10) << "traverse: absolute symlink, path now " << path << " depth " << depth << dendl;
         } else {
@@ -5413,7 +5432,7 @@ int MDCache::path_traverse(MDRequest *mdr, Message *req,     // who
            reply->starts_with = MDiscoverReply::DENTRY;
            replicate_dentry(dn, from, reply->trace);
            if (dn->is_primary())
-             replicate_inode(dn->inode, from, reply->trace);
+             replicate_inode(in, from, reply->trace);
            mds->send_message_mds(reply, req->get_source().num());
          }
        }
@@ -5421,7 +5440,7 @@ int MDCache::path_traverse(MDRequest *mdr, Message *req,     // who
       
       // add to trace, continue.
       trace.push_back(dn);
-      cur = dn->inode;
+      cur = in;
       touch_inode(cur);
       depth++;
       continue;
@@ -5655,11 +5674,14 @@ void MDCache::open_remote_dirfrag(CInode *diri, frag_t approxfg, Context *fin)
  *
  * will return inode for primary, or link up/open up remote link's inode as necessary.
  */
-CInode *MDCache::get_dentry_inode(CDentry *dn, MDRequest *mdr)
+CInode *MDCache::get_dentry_inode(CDentry *dn, MDRequest *mdr, bool projected)
 {
+  if (projected && dn->projected_inode)
+    return dn->projected_inode;
+
   assert(!dn->is_null());
   
-  if (dn->is_primary()) 
+  if (dn->is_primary())
     return dn->inode;
 
   assert(dn->is_remote());
index 314b6430abc4bda771b444ff77a921ee317efc95..cec5e65ef5a790bbdd3a99f31c0f023ba3ae1030 100644 (file)
@@ -857,7 +857,8 @@ public:
   int path_traverse(MDRequest *mdr, Message *req, filepath& path, 
                    vector<CDentry*>& trace, snapid_t *psnap, CInode **psnapdiri,
                    bool follow_trailing_sym,
-                    int onfail);
+                    int onfail,
+                   bool allow_projected=false);
   bool path_is_mine(filepath& path);
   bool path_is_mine(string& p) {
     filepath path(p);
@@ -868,7 +869,7 @@ public:
   int inopath_traverse(MDRequest *mdr, vector<ceph_inopath_item>& inopath);
   
   void open_remote_dirfrag(CInode *diri, frag_t fg, Context *fin);
-  CInode *get_dentry_inode(CDentry *dn, MDRequest *mdr);
+  CInode *get_dentry_inode(CDentry *dn, MDRequest *mdr, bool projected=false);
   void open_remote_ino(inodeno_t ino, Context *fin, inodeno_t hadino=0, version_t hadv=0);
   void open_remote_ino_2(inodeno_t ino,
                          vector<Anchor>& anchortrace,
index 87a948388ffed7de05db01efe48714c39da88138..52aead7c750c04a08a2a63f3d733057f54e83be9 100644 (file)
@@ -540,7 +540,7 @@ void Server::early_reply(MDRequest *mdr, CInode *tracei, CDentry *tracedn)
   snapid_t snapid = CEPH_NOSNAP;
   CInode *snapdiri = 0;
   if (tracei || tracedn)
-    set_trace_dist(mdr->session, reply, tracei, tracedn, snapid, snapdiri, true);
+    set_trace_dist(mdr->session, reply, tracei, tracedn, snapid, snapdiri, true, mdr);
 
   mdr->did_early_reply = true;
 
@@ -663,7 +663,7 @@ void Server::encode_null_lease(bufferlist& bl)
  */
 void Server::set_trace_dist(Session *session, MClientReply *reply, CInode *in, CDentry *dn,
                            snapid_t snapid, CInode *snapdiri,
-                           bool projected)
+                           bool projected, MDRequest *mdr)
 {
   // inode, dentry, dir, ..., inode
   bufferlist bl;
@@ -717,17 +717,18 @@ void Server::set_trace_dist(Session *session, MClientReply *reply, CInode *in, C
   }
 
   if (!dn) {
-    if (projected)
+    if (projected && mdr) {
       dn = in->get_projected_parent_dn();
-    else
+      if (dn && mdr->locks.count(&dn->lock) == 0)  // only use projected value if we've locked it!
+       dn = NULL;
+    }
+    if (!dn)
       dn = in->get_parent_dn();
   }
   if (!dn) 
     goto done;
 
  dentry:
-  projected = false;
-
   ::encode(dn->get_name(), bl);
   if (snapid == CEPH_NOSNAP)
     lmask = mds->locker->issue_client_lease(dn, client, bl, now, session);
@@ -1431,7 +1432,8 @@ CDir *Server::traverse_to_auth_dir(MDRequest *mdr, vector<CDentry*> &trace, file
   snapid_t snapid;
   int r = mdcache->path_traverse(mdr, mdr->client_request,
                                 refpath, trace, &snapid, &mdr->ref_snapdiri,
-                                false, MDS_TRAVERSE_FORWARD);
+                                false, MDS_TRAVERSE_FORWARD,
+                                true);
   if (r > 0) return 0; // delayed
   if (r < 0) {
     reply_request(mdr, r);
@@ -1443,7 +1445,7 @@ CDir *Server::traverse_to_auth_dir(MDRequest *mdr, vector<CDentry*> &trace, file
   if (trace.empty())
     diri = mdcache->get_inode(refpath.get_ino());
   else
-    diri = mdcache->get_dentry_inode(trace[trace.size()-1], mdr);
+    diri = mdcache->get_dentry_inode(trace[trace.size()-1], mdr, true);
   if (!diri) 
     return 0; // opening inode.
 
@@ -1481,7 +1483,8 @@ CInode* Server::rdlock_path_pin_ref(MDRequest *mdr,
   int r = mdcache->path_traverse(mdr, req,
                                 refpath, 
                                 trace, &mdr->ref_snapid, &mdr->ref_snapdiri,
-                                req->follow_trailing_symlink(), MDS_TRAVERSE_FORWARD);
+                                req->follow_trailing_symlink(), MDS_TRAVERSE_FORWARD,
+                                true);
   if (r > 0) return false; // delayed
   if (r < 0) {  // error
     reply_request(mdr, r);
@@ -1510,7 +1513,7 @@ CInode* Server::rdlock_path_pin_ref(MDRequest *mdr,
     }
 
     // open ref inode
-    ref = mdcache->get_dentry_inode(dn, mdr);
+    ref = mdcache->get_dentry_inode(dn, mdr, true);
     if (!ref) return 0;
   }
   dout(10) << "ref is " << *ref << dendl;
@@ -2324,6 +2327,8 @@ void Server::handle_client_mknod(MDRequest *mdr)
   assert(newi);
 
   newi->projected_parent = dn;
+  dn->projected_inode = newi;
+
   newi->inode.rdev = req->head.args.mknod.rdev;
   newi->inode.mode = req->head.args.mknod.mode;
   if ((newi->inode.mode & S_IFMT) == 0)
@@ -2331,7 +2336,6 @@ void Server::handle_client_mknod(MDRequest *mdr)
   newi->inode.version = dn->pre_dirty() - 1;
   newi->inode.rstat.rfiles = 1;
 
-  newi->projected_parent = dn;
   dn->first = newi->first = follows+1;
     
   dout(10) << "mknod mode " << newi->inode.mode << " rdev " << newi->inode.rdev << dendl;
@@ -2376,6 +2380,8 @@ void Server::handle_client_mkdir(MDRequest *mdr)
 
   // it's a directory.
   newi->projected_parent = dn;
+  dn->projected_inode = newi;
+
   newi->inode.mode = req->head.args.mkdir.mode;
   newi->inode.mode &= ~S_IFMT;
   newi->inode.mode |= S_IFDIR;
@@ -2430,6 +2436,8 @@ void Server::handle_client_symlink(MDRequest *mdr)
 
   // it's a symlink
   newi->projected_parent = dn;
+  dn->projected_inode = newi;
+
   newi->inode.mode &= ~S_IFMT;
   newi->inode.mode |= S_IFLNK;
   newi->inode.mode |= 0777;     // ?
@@ -2488,7 +2496,7 @@ void Server::handle_client_link(MDRequest *mdr)
   vector<CDentry*> targettrace;
   int r = mdcache->path_traverse(mdr, req,
                                 targetpath, targettrace, NULL, NULL,
-                                false, MDS_TRAVERSE_DISCOVER);
+                                false, MDS_TRAVERSE_DISCOVER, true);
   if (r > 0) return; // wait
   if (targettrace.empty()) r = -EINVAL; 
   if (r < 0) {
@@ -2497,8 +2505,9 @@ void Server::handle_client_link(MDRequest *mdr)
   }
   
   // identify target inode
-  CInode *targeti = targettrace[targettrace.size()-1]->inode;
-  assert(targeti);
+  CInode *targeti = mdcache->get_dentry_inode(targettrace[targettrace.size()-1], mdr, true);
+  if (!targeti)
+    return;
 
   // dir?
   dout(7) << "target is " << *targeti << dendl;
@@ -3084,7 +3093,7 @@ void Server::handle_client_unlink(MDRequest *mdr)
 
   // get/open inode.
   mdr->trace.swap(trace);
-  CInode *in = mdcache->get_dentry_inode(dn, mdr);
+  CInode *in = mdcache->get_dentry_inode(dn, mdr, true);
   if (!in) return;
   dout(7) << "dn links to " << *in << dendl;
 
@@ -3914,6 +3923,7 @@ void Server::_rename_prepare(MDRequest *mdr,
       pi->version = mdr->more()->pvmap[destdn] = destdn->pre_dirty(oldpv);
     }
     srcdn->inode->projected_parent = destdn;
+    destdn->projected_inode = srcdn->inode;
   }
 
   // src
@@ -5093,6 +5103,8 @@ void Server::handle_client_openc(MDRequest *mdr)
   
   // it's a file.
   in->projected_parent = dn;
+  dn->projected_inode = in;
+
   in->inode.mode = req->head.args.open.mode;
   in->inode.mode |= S_IFREG;
   in->inode.version = dn->pre_dirty() - 1;
index 4f5619dbd930d2f4e54d2ad69cf4d4d7bc534f81..20e8db88ad52d7d440bf1c245f1f7e0cc6f8f0ea 100644 (file)
@@ -80,7 +80,7 @@ public:
   void reply_request(MDRequest *mdr, MClientReply *reply, CInode *tracei = 0, CDentry *tracedn = 0);
   void set_trace_dist(Session *session, MClientReply *reply, CInode *in, CDentry *dn,
                      snapid_t snapid, CInode *snapdiri,
-                     bool projected = false);
+                     bool projected = false, MDRequest *mdr = 0);
 
   void encode_empty_dirstat(bufferlist& bl);
   void encode_infinite_lease(bufferlist& bl);