]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
generic ClientReplica + mask
authorSage Weil <sage@newdream.net>
Mon, 24 Mar 2008 23:21:10 +0000 (16:21 -0700)
committerSage Weil <sage@newdream.net>
Mon, 24 Mar 2008 23:21:10 +0000 (16:21 -0700)
src/TODO
src/client/Client.cc
src/client/Client.h
src/client/fuse.cc
src/include/ceph_fs.h
src/include/types.h
src/mds/Locker.cc
src/mds/Server.cc
src/mds/SimpleLock.h
src/mds/mdstypes.h
src/messages/MClientReply.h

index 1ec6ec705037721b8721c6b72ee9caa0c3c6f430..75301c171034a1159608b7ec4cab404f1c7e7803 100644 (file)
--- a/src/TODO
+++ b/src/TODO
@@ -4,6 +4,10 @@ code cleanup
   - probably kill base case in encoder.h, replace with int types, with appropriate swabbing?
 - addr=?
 
+client leases
+- clean up readdir vs stat leases
+  - esp on client.. keep mask/ttl and onetime_mask/onetime_ttl?
+
 kernel client
 - make sure link/unlink results reflected by inode/dentry cache  (let fill_trace do it?  invalidate?  do actual update?)
 - procfs/debugfs
index f8ea87c61a6d3b4022f6338a000bedfff31d6ebb..acda8792fe74fc0a674be76b59cf108c4a780c0a 100644 (file)
@@ -320,7 +320,7 @@ void Client::trim_cache()
  *
  * insert + link a single dentry + inode into the metadata cache.
  */
-Inode* Client::insert_inode(Dir *dir, InodeStat *st, const string& dname)
+Inode* Client::insert_inode(Dir *dir, InodeStat *st, const string& dname, utime_t ttl)
 {
   Dentry *dn = NULL;
   if (dir->dentries.count(dname))
@@ -376,17 +376,17 @@ Inode* Client::insert_inode(Dir *dir, InodeStat *st, const string& dname)
   } else {
     // actually update info
     dout(12) << " stat inode mask is " << st->mask << dendl;
-    if (st->mask & STAT_MASK_BASE) {
+    if (st->mask & CEPH_STAT_MASK_INODE) {
       dn->inode->inode = st->inode;
       dn->inode->dirfragtree = st->dirfragtree;  // FIXME look at the mask!
     }
 
     // ...but don't clobber our mtime, size!
     /* isn't this handled below?
-    if ((dn->inode->mask & STAT_MASK_SIZE) == 0 &&
+    if ((dn->inode->mask & CEPH_STAT_MASK_SIZE) == 0 &&
         dn->inode->file_wr_size > dn->inode->inode.size) 
       dn->inode->inode.size = dn->inode->file_wr_size;
-    if ((dn->inode->mask & STAT_MASK_MTIME) == 0 &&
+    if ((dn->inode->mask & CEPH_STAT_MASK_MTIME) == 0 &&
         dn->inode->file_wr_mtime > dn->inode->inode.mtime) 
       dn->inode->inode.mtime = dn->inode->file_wr_mtime;
     */
@@ -397,6 +397,7 @@ Inode* Client::insert_inode(Dir *dir, InodeStat *st, const string& dname)
 
   // save the mask
   dn->inode->mask = st->mask;
+  dn->inode->ttl = ttl;
   
   // or do we have newer size/mtime from writing?
   if (dn->inode->file_wr_size > dn->inode->inode.size)
@@ -478,27 +479,23 @@ Inode* Client::insert_trace(MClientReply *reply)
         inode_map[root->inode.ino] = root;
        root->dir_auth = 0;
       }
+      cur->ttl = ttl;
+      cur->mask = (*pin)->mask;
     } else {
       // not root.
       Dir *dir = cur->open_dir();
       assert(pdn != reply->get_trace_dn().end());
-      cur = this->insert_inode(dir, *pin, *pdn);
+      cur = this->insert_inode(dir, *pin, *pdn, ttl);
       dout(10) << "insert_trace dn " << *pdn << " ino " << (*pin)->inode.ino << " -> " << cur << dendl;
       ++pdn;      
 
-      // move to top of lru!
+      // touch dn
       if (cur->dn) {
         lru.lru_touch(cur->dn);
        cur->dn->ttl = ttl;
       }
     }
 
-    // set cache ttl
-    if (g_conf.client_cache_stat_ttl) {
-      cur->valid_until = now;
-      cur->valid_until += g_conf.client_cache_stat_ttl;
-    }
-
     // update dir dist info
     if (pdir == reply->get_trace_dir().end()) break;
     update_dir_dist(cur, *pdir);
@@ -510,12 +507,21 @@ Inode* Client::insert_trace(MClientReply *reply)
 
 
 
-
+/*
+ * bleh, dentry vs inode semantics here are sloppy
+ */
 Dentry *Client::lookup(filepath& path)
 {
   dout(14) << "lookup " << path << dendl;
 
-  Inode *cur = root;
+  Inode *cur;
+  if (path.get_ino()) {
+    if (inode_map.count(path.get_ino()))
+      cur = inode_map[path.get_ino()];
+    else
+      return NULL;
+  } else
+    cur = root;
   if (!cur) return NULL;
 
   Dentry *dn = 0;
@@ -526,7 +532,7 @@ Dentry *Client::lookup(filepath& path)
       Dir *dir = cur->dir;
       if (dir->dentries.count(path[i])) {
         dn = dir->dentries[path[i]];
-        dout(14) << " hit dentry " << path[i] << " inode is " << dn->inode << " valid_until " << dn->inode->valid_until << dendl;
+        dout(14) << " hit dentry " << path[i] << " inode is " << dn->inode << " ttl " << dn->inode->ttl << dendl;
       } else {
         dout(14) << " dentry " << path[i] << " dne" << dendl;
         return NULL;
@@ -537,9 +543,11 @@ Dentry *Client::lookup(filepath& path)
       return NULL;  // not a dir
     }
   }
-  
+
+  if (!dn) 
+    dn = cur->dn;
   if (dn) {
-    dout(11) << "lookup '" << path << "' found " << dn->name << " inode " << dn->inode->inode.ino << " valid_until " << dn->inode->valid_until<< dendl;
+    dout(11) << "lookup '" << path << "' found " << dn->name << " inode " << dn->inode->inode.ino << " ttl " << dn->inode->ttl << dendl;
   }
 
   return dn;
@@ -1510,7 +1518,7 @@ int Client::mount()
   //  fuse assumes it's always there.
   Inode *root;
   filepath fpath("", 1);
-  _do_lstat(fpath, STAT_MASK_ALL, &root);
+  _do_lstat(fpath, CEPH_STAT_MASK_INODE_ALL, &root);
   _ll_get(root);
 
   // trace?
@@ -1963,7 +1971,7 @@ int Client::_readlink(const char *path, char *buf, off_t size)
 { 
   Inode *in;
   filepath fpath(path);
-  int r = _do_lstat(fpath, STAT_MASK_BASE, &in);
+  int r = _do_lstat(fpath, CEPH_STAT_MASK_SYMLINK, &in);
   if (r == 0 && !in->inode.is_symlink()) r = -EINVAL;
   if (r == 0) {
     // copy into buf (at most size bytes)
@@ -1994,27 +2002,30 @@ int Client::_do_lstat(filepath &fpath, int mask, Inode **in)
   inode_t inode;
   utime_t now = g_clock.real_now();
 
-  if (dn && 
-      now <= dn->inode->valid_until)
-    dout(10) << "_lstat has inode " << fpath << " with mask " << dn->inode->mask << ", want " << mask << dendl;
+  if (dn) {
+    if (now <= dn->inode->ttl) {
+      dout(10) << "_lstat has inode " << fpath << " with mask " << dn->inode->mask << ", want " << mask << dendl;
+    } else {
+      dout(10) << "_lstat has EXPIRED (" << dn->inode->ttl << ") inode " << fpath
+              << " with mask " << dn->inode->mask << ", want " << mask 
+              << dendl;
+    }
+  } else {
+    dout(10) << "_lstat has no dn for path " << fpath << dendl;
+  }
   
   if (dn && dn->inode &&
-      now <= dn->inode->valid_until &&
-      ((mask & ~STAT_MASK_BASE) || now <= dn->inode->valid_until) &&
+      now <= dn->inode->ttl &&
+      ((mask & ~CEPH_STAT_MASK_INODE) || now <= dn->inode->ttl) &&
       ((dn->inode->mask & mask) == mask)) {
     inode = dn->inode->inode;
-    dout(10) << "lstat cache hit w/ sufficient mask, valid until " << dn->inode->valid_until << dendl;
+    dout(10) << "lstat cache hit w/ sufficient mask, valid until " << dn->inode->ttl << dendl;
     
-    if (g_conf.client_cache_stat_ttl == 0)
-      dn->inode->valid_until = utime_t();           // only one stat allowed after each readdir
+    //if (g_conf.client_cache_stat_ttl == 0)
+    //dn->inode->ttl = utime_t();           // only one stat allowed after each readdir
 
     *in = dn->inode;
   } else {  
-    // FIXME where does FUSE maintain user information
-    //struct fuse_context *fc = fuse_get_context();
-    //req->set_caller_uid(fc->uid);
-    //req->set_caller_gid(fc->gid);
-    
     req = new MClientRequest(CEPH_MDS_OP_LSTAT, messenger->get_myinst());
     req->head.args.stat.mask = mask;
     req->set_filepath(fpath);
@@ -2087,7 +2098,7 @@ int Client::_lstat(const char *path, struct stat *stbuf)
 {
   Inode *in = 0;
   filepath fpath(path);
-  int res = _do_lstat(fpath, STAT_MASK_ALL, &in);
+  int res = _do_lstat(fpath, CEPH_STAT_MASK_INODE_ALL, &in);
   if (res == 0) {
     assert(in);
     fill_stat(in, stbuf);
@@ -2478,7 +2489,8 @@ int Client::_readdir_get_frag(DirResult *dirp)
       // only open dir if we're actually adding stuff to it!
       Dir *dir = diri->open_dir();
       assert(dir);
-      utime_t now = g_clock.real_now();
+      utime_t ttl = g_clock.real_now();
+      ttl += 60.0;
       
       list<InodeStat*>::const_iterator pin = reply->get_dir_in().begin();
       for (list<string>::const_iterator pdn = reply->get_dir_dn().begin();
@@ -2488,17 +2500,7 @@ int Client::_readdir_get_frag(DirResult *dirp)
         res++;
        
        // put in cache
-       Inode *in = this->insert_inode(dir, *pin, *pdn);
-       
-       if (g_conf.client_cache_stat_ttl) {
-         in->valid_until = now;
-         in->valid_until += g_conf.client_cache_stat_ttl;
-       }
-       else if (g_conf.client_cache_readdir_ttl) {
-         in->valid_until = now;
-         in->valid_until += g_conf.client_cache_readdir_ttl;
-       } else 
-         in->valid_until = utime_t();
+       Inode *in = this->insert_inode(dir, *pin, *pdn, ttl);
        
        // contents to caller too!
        dout(15) << "_readdir_get_frag got " << *pdn << " to " << in->inode.ino << dendl;
@@ -3299,7 +3301,7 @@ int Client::_fstat(Fh *f, struct stat *stbuf)
 {
   Inode *in = 0;
   filepath fpath("", f->inode->ino());
-  int res = _do_lstat(fpath, STAT_MASK_ALL, &in);
+  int res = _do_lstat(fpath, CEPH_STAT_MASK_INODE_ALL, &in);
   if (res == 0) {
     assert(in);
     fill_stat(in, stbuf);
@@ -3624,7 +3626,7 @@ int Client::ll_getattr(inodeno_t ino, struct stat *attr)
 
   Inode *in = _ll_get_inode(ino);
   filepath fpath("", in->ino());
-  int res = _do_lstat(fpath, STAT_MASK_ALL, &in);
+  int res = _do_lstat(fpath, CEPH_STAT_MASK_INODE_ALL, &in);
   if (res == 0)
     fill_stat(in, attr);
   return res;
index 16ce0b428709bbf2b2f25655d283b140912d2c47..de585ec1d8f3dd285ea9b33fd0ec6edccd40c02d 100644 (file)
@@ -129,8 +129,8 @@ class InodeCap {
 class Inode {
  public:
   inode_t   inode;    // the actual inode
-  utime_t   valid_until;
-  int mask;
+  int       mask;
+  utime_t   ttl;
 
   // about the dir (if this is one!)
   int       dir_auth;
@@ -197,7 +197,7 @@ class Inode {
 
   Inode(inode_t _inode, ObjectCacher *_oc) : 
     inode(_inode),
-    valid_until(0, 0),
+    mask(0),
     dir_auth(-1), dir_hashed(false), dir_replicated(false), 
     file_wr_mtime(0, 0), file_wr_size(0), 
     num_open_rd(0), num_open_wr(0), num_open_lazy(0),
@@ -693,7 +693,7 @@ protected:
   void unlock_fh_pos(Fh *f);
   
   // metadata cache
-  Inode* insert_inode(Dir *dir, InodeStat *in_info, const string& dn);
+  Inode* insert_inode(Dir *dir, InodeStat *in_info, const string& dn, utime_t ttl);
   void update_dir_dist(Inode *in, DirStat *st);
   Inode* insert_trace(MClientReply *reply);
 
index 10d7c24bf8d771777cc4d93cdef6bef5e4f0a034..963f3ef7b92291ecfe630034c9f591e19576ec77 100644 (file)
@@ -206,7 +206,7 @@ static int ceph_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off
   while (res == 0) {
     int r = client->readdirplus_r(dirp, &de, &st, &stmask);
     if (r != 0) break;
-    int stneed = STAT_MASK_INO | STAT_MASK_TYPE;
+    int stneed = CEPH_STAT_MASK_INODE | CEPH_STAT_MASK_TYPE;
     res = filler(buf,
                  de.d_name,
                 ((stmask & stneed) == stneed) ? &st:0,
index 27d5f1fd9be3b3a0ca74733008f1f5c98d9382a3..c971d825a9d68803922d2ddb2eb0eec9d81b50ac 100644 (file)
@@ -308,6 +308,29 @@ struct ceph_statfs {
 #define CEPH_MDS_STATE_STOPPING    13 /* up, exporting metadata */
 
 
+/*
+ * metadata/stat validity masks
+ */
+#define CEPH_STAT_MASK_INODE    1   /* immutable inode bits */
+#define CEPH_STAT_MASK_AUTH     2
+#define CEPH_STAT_MASK_LINK     4
+#define CEPH_STAT_MASK_FILE     8
+#define CEPH_STAT_MASK_INODE_ALL 15
+
+#define CEPH_STAT_MASK_DN       64  /* dentry */
+
+#define CEPH_STAT_MASK_TYPE     CEPH_STAT_MASK_INODE  /* mode >> 12 */
+#define CEPH_STAT_MASK_SYMLINK  CEPH_STAT_MASK_INODE
+#define CEPH_STAT_MASK_LAYOUT   CEPH_STAT_MASK_INODE
+#define CEPH_STAT_MASK_UID      CEPH_STAT_MASK_AUTH
+#define CEPH_STAT_MASK_GID      CEPH_STAT_MASK_AUTH
+#define CEPH_STAT_MASK_MODE     CEPH_STAT_MASK_AUTH
+#define CEPH_STAT_MASK_NLINK    CEPH_STAT_MASK_LINK
+#define CEPH_STAT_MASK_MTIME    CEPH_STAT_MASK_FILE
+#define CEPH_STAT_MASK_SIZE     CEPH_STAT_MASK_FILE
+#define CEPH_STAT_MASK_ATIME    CEPH_STAT_MASK_FILE  /* fixme */
+
+
 /* client_session */
 enum {
        CEPH_SESSION_REQUEST_OPEN,
index 3f515c10e02e8b864b2b8103840acf94b30f7254..2e7cbafa22c1956c54900f2fe5649cf96354b2fb 100644 (file)
@@ -155,21 +155,6 @@ namespace __gnu_cxx {
 #define FILE_MODE_RW         (1|2)
 #define FILE_MODE_LAZY       4
 
-/** stat masks
- */
-#define STAT_MASK_INO        1   // inode nmber
-#define STAT_MASK_TYPE       2   // file type bits of the mode
-#define STAT_MASK_BASE       4   // layout, symlink value
-#define STAT_MASK_AUTH       8   // uid, gid, mode
-#define STAT_MASK_LINK       16   // nlink, anchored
-#define STAT_MASK_FILE       32  // mtime, size.
-
-#define STAT_MASK_ALL        63
-
-#define STAT_MASK_SIZE       STAT_MASK_FILE // size, blksize, blocks
-#define STAT_MASK_MTIME      STAT_MASK_FILE // mtime
-#define STAT_MASK_ATIME      STAT_MASK_FILE // atime
-#define STAT_MASK_CTIME      (STAT_MASK_FILE|STAT_MASK_AUTH|STAT_MASK_LINK) // ctime
 
 inline int DT_TO_MODE(int dt) {
   return dt << 12;
index ea5a62825f1a585afa08ad0716c499259552efe5..640260a89e9dbdc9b9060b8ff64a5697e15df2a4 100644 (file)
@@ -1245,13 +1245,13 @@ void Locker::simple_lock(SimpleLock *lock)
   assert(lock->get_state() == LOCK_SYNC);
   
   if (lock->get_parent()->is_replicated() ||
-      lock->get_num_clients()) {
+      lock->get_parent()->is_client_replicated()) {
     // bcast to mds replicas
     send_lock_message(lock, LOCK_AC_LOCK);
 
     // bcast to client replicas
-    for (hash_map<int, ClientReplica*>::iterator p = lock->client_set.begin();
-        p != lock->client_set.end();
+    for (hash_map<int, ClientReplica*>::iterator p = lock->get_parent()->client_replica_map.begin();
+        p != lock->get_parent()->client_replica_map.end();
         p++) {
       ClientReplica *r = p->second;
       if (lock->get_type() == LOCK_OTYPE_DN) {
index e69d7fa47ad3457a3cfa7a854de0bd05fc3d4494..71c8f1031f9d3bf9ebcbad400c753f22578da370 100644 (file)
@@ -562,20 +562,23 @@ void Server::set_trace_dist(Session *session, MClientReply *reply, CInode *in)
   __u32 numi = 0;
   utime_t ttl = g_clock.now();
   ttl += 60.0;  // FIXME
+  ClientReplica *r;
 
   while (true) {
     // inode
-    InodeStat::_encode(bl, in);
+    r = in->get_client_replica(client);
+    r->ttl = ttl;
+    r->mask |= InodeStat::_encode(bl, in);
     numi++;
+
     CDentry *dn = in->get_parent_dn();
     if (!dn) break;
     
     // dentry
     ::_encode_simple(dn->get_name(), bl);
-    ClientReplica *r = dn->lock.client_set[client];
-    if (!r) 
-      r = dn->lock.client_set[client] = new ClientReplica(client, &dn->lock);
+    r = dn->get_client_replica(client);
     r->ttl = ttl;
+    r->mask = CEPH_STAT_MASK_DN;
     session->replicas.push_back(&r->session_replica_item);
     
     // dir
@@ -1477,12 +1480,12 @@ void Server::handle_client_stat(MDRequest *mdr)
   set<SimpleLock*> xlocks = mdr->xlocks;
   
   int mask = req->head.args.stat.mask;
-  if (mask & STAT_MASK_LINK) rdlocks.insert(&ref->linklock);
-  if (mask & STAT_MASK_AUTH) rdlocks.insert(&ref->authlock);
+  if (mask & CEPH_STAT_MASK_LINK) rdlocks.insert(&ref->linklock);
+  if (mask & CEPH_STAT_MASK_AUTH) rdlocks.insert(&ref->authlock);
   if (ref->is_file() && 
-      mask & STAT_MASK_FILE) rdlocks.insert(&ref->filelock);
+      mask & CEPH_STAT_MASK_FILE) rdlocks.insert(&ref->filelock);
   if (ref->is_dir() &&
-      mask & STAT_MASK_MTIME) rdlocks.insert(&ref->dirlock);
+      mask & CEPH_STAT_MASK_MTIME) rdlocks.insert(&ref->dirlock);
 
   if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks))
     return;
index 4df2d7618feb1524aff66053a6f67eb51d27d60e..720247bc55a84aa5801e0d80c0db8d47d349a865 100644 (file)
@@ -106,9 +106,6 @@ protected:
   int num_rdlock;
   MDRequest *xlock_by;
 
-public:
-  hash_map<int, ClientReplica*> client_set; // auth+rep
-
 
 public:
   SimpleLock(MDSCacheObject *o, int t, int wo) :
@@ -177,8 +174,8 @@ public:
         p != parent->replicas_end(); 
         ++p)
       gather_set.insert(p->first);
-    for (hash_map<int,ClientReplica*>::const_iterator p = client_set.begin();
-        p != client_set.end();
+    for (hash_map<int,ClientReplica*>::const_iterator p = parent->client_replica_map.begin();
+        p != parent->client_replica_map.end();
         p++)
       gather_set.insert(-1 - p->second->client);
   }
@@ -223,10 +220,8 @@ public:
   }
   MDRequest *get_xlocked_by() { return xlock_by; }
   
-  int get_num_clients() { return client_set.size(); }
-
   bool is_used() {
-    return is_xlocked() || is_rdlocked() || !client_set.empty();
+    return is_xlocked() || is_rdlocked() || !parent->client_replica_map.empty();
   }
 
   // encode/decode
@@ -312,8 +307,8 @@ public:
     out << get_lock_type_name(get_type()) << " ";
     out << get_simplelock_state_name(get_state());
     if (!get_gather_set().empty()) out << " g=" << get_gather_set();
-    if (!client_set.empty())
-      out << " c=" << client_set.size();
+    if (!parent->client_replica_map.empty())
+      out << " c=" << parent->client_replica_map.size();
     if (is_rdlocked()) 
       out << " r=" << get_num_rdlocks();
     if (is_xlocked())
index 0ea82dff69b31c4a74065d76fac4d1681401603c..0adcca0b230738512ce8bf091f8585737f7f67ec 100644 (file)
@@ -339,6 +339,20 @@ class MDSCacheObject;
 //#define CDIR_AUTH_ROOTINODE pair<int,int>( 0, -2)
 
 
+/*
+ * for metadata leases to clients
+ */
+struct ClientReplica {
+  int client;
+  int mask;                 // CEPH_STAT_MASK_*
+  utime_t ttl;
+  MDSCacheObject *parent;
+  xlist<ClientReplica*>::item session_replica_item;
+  ClientReplica(int c) : 
+    client(c), mask(0),
+    session_replica_item(this) { }
+};
+
 
 // print hack
 struct mdsco_db_line_prefix {
@@ -542,9 +556,9 @@ protected:
 
 
   // --------------------------------------------
-  // replication
+  // replication (across mds cluster)
  protected:
-  map<int,int> replica_map;      // [auth] mds -> nonce
+  map<int,int> replica_map;   // [auth] mds -> nonce
   int          replica_nonce; // [replica] defined on replica
 
  public:
@@ -592,6 +606,22 @@ protected:
   void set_replica_nonce(int n) { replica_nonce = n; }
 
 
+  // ---------------------------------------------
+  // replicas (on clients)
+ public:
+  hash_map<int,ClientReplica*> client_replica_map;
+  
+  ClientReplica *get_client_replica(int c) {
+    if (client_replica_map.count(c))
+      return client_replica_map[c];
+    else
+      return client_replica_map[c] = new ClientReplica(c);
+  }
+  bool is_client_replicated() {
+    return !client_replica_map.empty();
+  }
+  
+
   // ---------------------------------------------
   // waiting
  protected:
@@ -682,14 +712,6 @@ inline ostream& operator<<(ostream& out, mdsco_db_line_prefix o) {
 }
 
 
-struct ClientReplica {
-  int client;
-  SimpleLock *lock;
-  utime_t ttl;
-  xlist<ClientReplica*>::item session_replica_item;
-  ClientReplica(int c, SimpleLock *l) : client(c), lock(l),
-                                       session_replica_item(this) { }
-};
 
 
 #endif
index 8387cf9bf1d888f65c5914a1e4c19bc6c1576a0b..4a721ea7e98735e0497420a3df843d003512a2ac 100644 (file)
@@ -130,13 +130,12 @@ struct InodeStat {
     mask = e.mask;
   }
 
-  static void _encode(bufferlist &bl, CInode *in) {
-    int mask = STAT_MASK_INO|STAT_MASK_TYPE|STAT_MASK_BASE;
-
+  static int _encode(bufferlist &bl, CInode *in) {
     // mask
-    if (in->authlock.can_rdlock(0)) mask |= STAT_MASK_AUTH;
-    if (in->linklock.can_rdlock(0)) mask |= STAT_MASK_LINK;
-    if (in->filelock.can_rdlock(0)) mask |= STAT_MASK_FILE;
+    int mask = CEPH_STAT_MASK_INODE;
+    if (in->authlock.can_rdlock(0)) mask |= CEPH_STAT_MASK_AUTH;
+    if (in->linklock.can_rdlock(0)) mask |= CEPH_STAT_MASK_LINK;
+    if (in->filelock.can_rdlock(0)) mask |= CEPH_STAT_MASK_FILE;
 
     /*
      * note: encoding matches struct ceph_client_reply_inode
@@ -165,6 +164,8 @@ struct InodeStat {
       ::_encode_simple(p->second, bl);
     }
     ::_encode_simple(in->symlink, bl);
+
+    return mask;
   }
   
 };