]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Merge remote-tracking branch 'origin/master' into wip-getuid
authorGreg Farnum <gfarnum@redhat.com>
Sat, 24 Sep 2016 01:12:33 +0000 (18:12 -0700)
committerGreg Farnum <gfarnum@redhat.com>
Sat, 24 Sep 2016 01:12:33 +0000 (18:12 -0700)
Conflicts:
src/client/Client.cc
src/client/Client.h
src/client/Makefile.am
src/client/fuse_ll.cc

Signed-off-by: Greg Farnum <gfarnum@redhat.com>
1  2 
src/client/Client.cc
src/client/Client.h
src/client/Inode.cc
src/client/Inode.h
src/client/MetaRequest.h
src/common/config_opts.h
src/libcephfs.cc
src/mds/Locker.cc
src/mds/Server.cc
src/mds/SessionMap.cc
src/messages/MClientRequest.h

index 256f6060b5e5c51915b20a2697d017bcea218b26,0339c2807dbf4b523f28023b5e8afa38078afafa..a764e87f240dc6a5bef8a3768e0ba4dcead9aaa0
    return r;
  }
  
 -int Client::may_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid)
 -{
 -  if (uid < 0)
 -    uid = get_uid();
 -  if (gid < 0)
 -    gid = get_gid();
 -  RequestUserGroups groups(this, uid, gid);
 +ostream& operator<<(ostream &out, const UserPerm& perm) {
 +  out << "UserPerm(uid: " << perm.uid() << ", gid: " << perm.gid() << ")";
 +  return out;
 +}
  
- int Client::may_setattr(Inode *in, struct stat *st, int mask, const UserPerm& perms)
 -  int r = _getattr_for_perm(in, uid, gid);
++int Client::may_setattr(Inode *in, struct ceph_statx *stx, int mask,
++                      const UserPerm& perms)
 +{
 +  ldout(cct, 20) << __func__ << *in << "; " << perms << dendl;
 +  int r = _getattr_for_perm(in, perms);
    if (r < 0)
      goto out;
  
  
    r = -EPERM;
    if (mask & CEPH_SETATTR_UID) {
-     if (perms.uid() != 0 && (perms.uid() != in->uid || st->st_uid != in->uid))
 -    if (uid != 0 && ((uid_t)uid != in->uid || stx->stx_uid != in->uid))
++    if (perms.uid() != 0 && (perms.uid() != in->uid || stx->stx_uid != in->uid))
        goto out;
    }
    if (mask & CEPH_SETATTR_GID) {
 -    if (uid != 0 && ((uid_t)uid != in->uid ||
 -          (!groups.is_in(stx->stx_gid) && stx->stx_gid != in->gid)))
 +    if (perms.uid() != 0 && (perms.uid() != in->uid ||
-                      (!perms.gid_in_groups(st->st_gid) && st->st_gid != in->gid)))
++                     (!perms.gid_in_groups(stx->stx_gid) && stx->stx_gid != in->gid)))
        goto out;
    }
  
    if (mask & CEPH_SETATTR_MODE) {
 -    if (uid != 0 && (uid_t)uid != in->uid)
 +    if (perms.uid() != 0 && perms.uid() != in->uid)
        goto out;
  
-     gid_t i_gid = (mask & CEPH_SETATTR_GID) ? st->st_gid : in->gid;
+     gid_t i_gid = (mask & CEPH_SETATTR_GID) ? stx->stx_gid : in->gid;
 -    if (uid != 0 && !groups.is_in(i_gid))
 +    if (perms.uid() != 0 && !perms.gid_in_groups(i_gid))
-       st->st_mode &= ~S_ISGID;
+       stx->stx_mode &= ~S_ISGID;
    }
  
-   if (mask & (CEPH_SETATTR_CTIME | CEPH_SETATTR_MTIME | CEPH_SETATTR_ATIME)) {
 -  if (mask & (CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME | CEPH_SETATTR_MTIME | CEPH_SETATTR_ATIME)) {
 -    if (uid != 0 && (uid_t)uid != in->uid) {
++  if (mask & (CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME |
++            CEPH_SETATTR_MTIME | CEPH_SETATTR_ATIME)) {
 +    if (perms.uid() != 0 && perms.uid() != in->uid) {
-       int check_mask = CEPH_SETATTR_CTIME;
+       int check_mask = CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME;
        if (!(mask & CEPH_SETATTR_MTIME_NOW))
        check_mask |= CEPH_SETATTR_MTIME;
        if (!(mask & CEPH_SETATTR_ATIME_NOW))
@@@ -6015,8 -6048,8 +6034,9 @@@ int Client::get_or_create(Inode *dir, c
    return 0;
  }
  
 -int Client::path_walk(const filepath& origpath, InodeRef *end, bool followsym,
 +int Client::path_walk(const filepath& origpath, InodeRef *end,
-                     const UserPerm& perms, bool followsym)
++                    const UserPerm& perms, bool followsym,
+                     int mask, int uid, int gid)
  {
    filepath path = origpath;
    InodeRef cur;
        return r;
        caps = CEPH_CAP_AUTH_SHARED;
      }
 -
 -    int r = _lookup(cur.get(), dname, caps, &next, uid, gid);
+     /* Get extra requested caps on the last component */
+     if (i == (path.depth() - 1))
+       caps |= mask;
 +    int r = _lookup(cur.get(), dname, caps, &next, perms);
      if (r < 0)
        return r;
      // only follow trailing symlink if followsym.  always follow
@@@ -6379,8 -6425,8 +6403,8 @@@ int Client::_getattr(Inode *in, int mas
    return res;
  }
  
- int Client::_do_setattr(Inode *in, struct stat *attr, int mask,
 -int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid,
 -                      InodeRef *inp)
++int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask,
 +                      const UserPerm& perms, InodeRef *inp)
  {
    int issued = in->caps_issued();
  
      return -EROFS;
    }
    if ((mask & CEPH_SETATTR_SIZE) &&
-       (unsigned long)attr->st_size > in->size &&
-       is_quota_bytes_exceeded(in, (unsigned long)attr->st_size - in->size,
+       (unsigned long)stx->stx_size > in->size &&
 -      is_quota_bytes_exceeded(in, (unsigned long)stx->stx_size - in->size)) {
++      is_quota_bytes_exceeded(in, (unsigned long)stx->stx_size - in->size,
 +                            perms)) {
      return -EDQUOT;
    }
  
    if (in->caps_issued_mask(CEPH_CAP_AUTH_EXCL)) {
      if (mask & CEPH_SETATTR_MODE) {
        in->ctime = ceph_clock_now(cct);
 -      in->cap_dirtier_uid = uid;
 -      in->cap_dirtier_gid = gid;
 +      in->cap_dirtier_uid = perms.uid();
 +      in->cap_dirtier_gid = perms.gid();
-       in->mode = (in->mode & ~07777) | (attr->st_mode & 07777);
+       in->mode = (in->mode & ~07777) | (stx->stx_mode & 07777);
        mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL);
        mask &= ~CEPH_SETATTR_MODE;
-       ldout(cct,10) << "changing mode to " << attr->st_mode << dendl;
+       ldout(cct,10) << "changing mode to " << stx->stx_mode << dendl;
      }
      if (mask & CEPH_SETATTR_UID) {
        in->ctime = ceph_clock_now(cct);
 -      in->cap_dirtier_uid = uid;
 -      in->cap_dirtier_gid = gid;
 +      in->cap_dirtier_uid = perms.uid();
 +      in->cap_dirtier_gid = perms.gid();
-       in->uid = attr->st_uid;
+       in->uid = stx->stx_uid;
        mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL);
        mask &= ~CEPH_SETATTR_UID;
-       ldout(cct,10) << "changing uid to " << attr->st_uid << dendl;
+       ldout(cct,10) << "changing uid to " << stx->stx_uid << dendl;
      }
      if (mask & CEPH_SETATTR_GID) {
        in->ctime = ceph_clock_now(cct);
 -      in->cap_dirtier_uid = uid;
 -      in->cap_dirtier_gid = gid;
 +      in->cap_dirtier_uid = perms.uid();
 +      in->cap_dirtier_gid = perms.gid();
-       in->gid = attr->st_gid;
+       in->gid = stx->stx_gid;
        mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL);
        mask &= ~CEPH_SETATTR_GID;
-       ldout(cct,10) << "changing gid to " << attr->st_gid << dendl;
+       ldout(cct,10) << "changing gid to " << stx->stx_gid << dendl;
+     }
+     if (mask & CEPH_SETATTR_BTIME) {
+       in->ctime = ceph_clock_now(cct);
 -      in->cap_dirtier_uid = uid;
 -      in->cap_dirtier_gid = gid;
++      in->cap_dirtier_uid = perms.uid();
++      in->cap_dirtier_gid = perms.gid();
+       in->btime = utime_t(stx->stx_btime);
+       mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL);
+       mask &= ~CEPH_SETATTR_BTIME;
+       ldout(cct,10) << "changing btime to " << in->btime << dendl;
      }
    }
    if (in->caps_issued_mask(CEPH_CAP_FILE_EXCL)) {
      if (mask & (CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME)) {
        if (mask & CEPH_SETATTR_MTIME)
-         in->mtime = utime_t(stat_get_mtime_sec(attr), stat_get_mtime_nsec(attr));
+         in->mtime = utime_t(stx->stx_mtime);
        if (mask & CEPH_SETATTR_ATIME)
-         in->atime = utime_t(stat_get_atime_sec(attr), stat_get_atime_nsec(attr));
+         in->atime = utime_t(stx->stx_atime);
        in->ctime = ceph_clock_now(cct);
 -      in->cap_dirtier_uid = uid;
 -      in->cap_dirtier_gid = gid;
 +      in->cap_dirtier_uid = perms.uid();
 +      in->cap_dirtier_gid = perms.gid();
        in->time_warp_seq++;
        mark_caps_dirty(in, CEPH_CAP_FILE_EXCL);
        mask &= ~(CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME);
@@@ -6535,34 -6600,52 +6574,55 @@@ force_request
    return res;
  }
  
- int Client::_setattr(Inode *in, struct stat *attr, int mask,
                   const UserPerm& perms, InodeRef *inp)
+ /* Note that we only care about attrs that setattr cares about */
void Client::stat_to_statx(struct stat *st, struct ceph_statx *stx)
  {
-   int ret = _do_setattr(in, attr, mask, perms, inp);
+   stx->stx_size = st->st_size;
+   stx->stx_mode = st->st_mode;
+   stx->stx_uid = st->st_uid;
+   stx->stx_gid = st->st_gid;
+   stx->stx_mtime = st->st_mtim;
+   stx->stx_atime = st->st_atim;
+ }
 -int Client::__setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid,
 -                   InodeRef *inp)
++int Client::__setattrx(Inode *in, struct ceph_statx *stx, int mask,
++                     const UserPerm& perms, InodeRef *inp)
+ {
 -  int ret = _do_setattr(in, stx, mask, uid, gid, inp);
++  int ret = _do_setattr(in, stx, mask, perms, inp);
    if (ret < 0)
     return ret;
    if (mask & CEPH_SETATTR_MODE)
-     ret = _posix_acl_chmod(in, attr->st_mode, perms);
 -    ret = _posix_acl_chmod(in, stx->stx_mode, uid, gid);
++    ret = _posix_acl_chmod(in, stx->stx_mode, perms);
    return ret;
  }
  
- int Client::_setattr(InodeRef &in, struct stat *attr, int mask,
-                    const UserPerm& perms)
 -int Client::_setattrx(InodeRef &in, struct ceph_statx *stx, int mask)
++int Client::_setattrx(InodeRef &in, struct ceph_statx *stx, int mask,
++                    const UserPerm& perms)
  {
    mask &= (CEPH_SETATTR_MODE | CEPH_SETATTR_UID |
           CEPH_SETATTR_GID | CEPH_SETATTR_MTIME |
           CEPH_SETATTR_ATIME | CEPH_SETATTR_SIZE |
-          CEPH_SETATTR_CTIME);
+          CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME);
    if (cct->_conf->client_permissions) {
-     int r = may_setattr(in.get(), attr, mask, perms);
 -    int r = may_setattr(in.get(), stx, mask);
++    int r = may_setattr(in.get(), stx, mask, perms);
      if (r < 0)
        return r;
    }
-   return _setattr(in.get(), attr, mask, perms);
 -  return __setattrx(in.get(), stx, mask);
++  return __setattrx(in.get(), stx, mask, perms);
+ }
 -int Client::_setattr(InodeRef &in, struct stat *attr, int mask)
++int Client::_setattr(InodeRef &in, struct stat *attr, int mask,
++                   const UserPerm& perms)
+ {
+   struct ceph_statx stx;
+   stat_to_statx(attr, &stx);
+   mask &= ~CEPH_SETATTR_BTIME;
 -  return _setattrx(in, &stx, mask);
++  return _setattrx(in, &stx, mask, perms);
  }
  
 -int Client::setattr(const char *relpath, struct stat *attr, int mask)
 +int Client::setattr(const char *relpath, struct stat *attr, int mask,
 +                  const UserPerm& perms)
  {
    Mutex::Locker lock(client_lock);
    tout(cct) << "setattr" << std::endl;
  
    filepath path(relpath);
    InodeRef in;
 -  int r = path_walk(path, &in);
 +  int r = path_walk(path, &in, perms);
    if (r < 0)
      return r;
 -  return _setattr(in, attr, mask);
 +  return _setattr(in, attr, mask, perms);
  }
  
- int Client::fsetattr(int fd, struct stat *attr, int mask,
-                    const UserPerm& perms)
 -int Client::setattrx(const char *relpath, struct ceph_statx *stx, int mask, int flags)
++int Client::setattrx(const char *relpath, struct ceph_statx *stx, int mask,
++                   const UserPerm& perms, int flags)
+ {
+   Mutex::Locker lock(client_lock);
+   tout(cct) << "setattrx" << std::endl;
+   tout(cct) << relpath << std::endl;
+   tout(cct) << mask  << std::endl;
+   filepath path(relpath);
+   InodeRef in;
 -  int r = path_walk(path, &in, flags & AT_SYMLINK_NOFOLLOW);
++  int r = path_walk(path, &in, perms, flags & AT_SYMLINK_NOFOLLOW);
+   if (r < 0)
+     return r;
 -  return _setattrx(in, stx, mask);
++  return _setattrx(in, stx, mask, perms);
+ }
 -int Client::fsetattr(int fd, struct stat *attr, int mask)
++int Client::fsetattr(int fd, struct stat *attr, int mask, const UserPerm& perms)
  {
    Mutex::Locker lock(client_lock);
    tout(cct) << "fsetattr" << std::endl;
@@@ -6604,10 -6701,10 +6679,10 @@@ int Client::stat(const char *relpath, s
    tout(cct) << relpath << std::endl;
    filepath path(relpath);
    InodeRef in;
-   int r = path_walk(path, &in, perms);
 -  int r = path_walk(path, &in, true, mask);
++  int r = path_walk(path, &in, perms, true, mask);
    if (r < 0)
      return r;
 -  r = _getattr(in, mask);
 +  r = _getattr(in, mask, perms);
    if (r < 0) {
      ldout(cct, 3) << "stat exit on error!" << dendl;
      return r;
    return r;
  }
  
 -  int r = path_walk(path, &in, flags & AT_SYMLINK_NOFOLLOW, mask);
+ unsigned Client::statx_to_mask(unsigned int flags, unsigned int want)
+ {
+   unsigned mask = 0;
+   /* if NO_ATTR_SYNC is set, then we don't need any -- just use what's in cache */
+   if (flags & AT_NO_ATTR_SYNC)
+     goto out;
+   /* Always set PIN to distinguish from AT_NO_ATTR_SYNC case */
+   mask |= CEPH_CAP_PIN;
+   if (want & (CEPH_STATX_MODE|CEPH_STATX_UID|CEPH_STATX_GID|CEPH_STATX_BTIME|CEPH_STATX_CTIME|CEPH_STATX_VERSION))
+     mask |= CEPH_CAP_AUTH_SHARED;
+   if (want & (CEPH_STATX_NLINK|CEPH_STATX_CTIME|CEPH_STATX_VERSION))
+     mask |= CEPH_CAP_LINK_SHARED;
+   if (want & (CEPH_STATX_ATIME|CEPH_STATX_MTIME|CEPH_STATX_CTIME|CEPH_STATX_SIZE|CEPH_STATX_BLOCKS|CEPH_STATX_VERSION))
+     mask |= CEPH_CAP_FILE_SHARED;
+   if (want & (CEPH_STATX_VERSION|CEPH_STATX_CTIME))
+     mask |= CEPH_CAP_XATTR_SHARED;
+ out:
+   return mask;
+ }
+ int Client::statx(const char *relpath, struct ceph_statx *stx,
++                const UserPerm& perms,
+                 unsigned int want, unsigned int flags)
+ {
+   ldout(cct, 3) << "statx enter (relpath " << relpath << " want " << want << ")" << dendl;
+   Mutex::Locker lock(client_lock);
+   tout(cct) << "statx" << std::endl;
+   tout(cct) << relpath << std::endl;
+   filepath path(relpath);
+   InodeRef in;
+   unsigned mask = statx_to_mask(flags, want);
 -    r = _getattr(in, mask);
++  int r = path_walk(path, &in, perms, flags & AT_SYMLINK_NOFOLLOW, mask);
+   if (r < 0)
+     return r;
+   if (mask && !in->caps_issued_mask(mask)) {
++    r = _getattr(in, mask, perms);
+     if (r < 0) {
+       ldout(cct, 3) << "statx exit on error!" << dendl;
+       return r;
+     }
+   }
+   fill_statx(in, mask, stx);
+   ldout(cct, 3) << "statx exit (relpath " << relpath << " mask " << stx->stx_mask << ")" << dendl;
+   return r;
+ }
  int Client::lstat(const char *relpath, struct stat *stbuf,
 -                        frag_info_t *dirstat, int mask)
 +                const UserPerm& perms, frag_info_t *dirstat, int mask)
  {
    ldout(cct, 3) << "lstat enter (relpath " << relpath << " mask " << mask << ")" << dendl;
    Mutex::Locker lock(client_lock);
    filepath path(relpath);
    InodeRef in;
    // don't follow symlinks
-   int r = path_walk(path, &in, perms, false);
 -  int r = path_walk(path, &in, false, mask);
++  int r = path_walk(path, &in, perms, false, mask);
    if (r < 0)
      return r;
 -  r = _getattr(in, mask);
 +  r = _getattr(in, mask, perms);
    if (r < 0) {
      ldout(cct, 3) << "lstat exit on error!" << dendl;
      return r;
@@@ -7530,7 -7742,7 +7722,7 @@@ int Client::open(const char *relpath, i
    bool created = false;
    /* O_CREATE with O_EXCL enforces O_NOFOLLOW. */
    bool followsym = !((flags & O_NOFOLLOW) || ((flags & O_CREAT) && (flags & O_EXCL)));
-   int r = path_walk(path, &in, perms, followsym);
 -  int r = path_walk(path, &in, followsym, ceph_caps_for_mode(mode), uid, gid);
++  int r = path_walk(path, &in, perms, followsym, ceph_caps_for_mode(mode));
  
    if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL))
      return -EEXIST;
      string dname = dirpath.last_dentry();
      dirpath.pop_dentry();
      InodeRef dir;
-     r = path_walk(dirpath, &dir, perms, true);
 -    r = path_walk(dirpath, &dir, true,
 -                cct->_conf->client_permissions ? CEPH_CAP_AUTH_SHARED : 0,
 -                uid, gid);
++    r = path_walk(dirpath, &dir, perms, true,
++                cct->_conf->client_permissions ? CEPH_CAP_AUTH_SHARED : 0);
      if (r < 0)
        goto out;
      if (cct->_conf->client_permissions) {
@@@ -8693,14 -8891,14 +8887,14 @@@ int Client::_flush(Fh *f
    return err;
  }
  
 -int Client::truncate(const char *relpath, loff_t length) 
 +int Client::truncate(const char *relpath, loff_t length, const UserPerm& perms
  {
-   struct stat attr;
-   attr.st_size = length;
-   return setattr(relpath, &attr, CEPH_SETATTR_SIZE, perms);
+   struct ceph_statx stx;
+   stx.stx_size = length;
 -  return setattrx(relpath, &stx, CEPH_SETATTR_SIZE);
++  return setattrx(relpath, &stx, CEPH_SETATTR_SIZE, perms);
  }
  
 -int Client::ftruncate(int fd, loff_t length) 
 +int Client::ftruncate(int fd, loff_t length, const UserPerm& perms
  {
    Mutex::Locker lock(client_lock);
    tout(cct) << "ftruncate" << std::endl;
@@@ -8832,6 -9030,31 +9026,32 @@@ int Client::fstat(int fd, struct stat *
    return r;
  }
  
 -int Client::fstatx(int fd, struct ceph_statx *stx, unsigned int want, unsigned int flags)
++int Client::fstatx(int fd, struct ceph_statx *stx, const UserPerm& perms,
++                 unsigned int want, unsigned int flags)
+ {
+   Mutex::Locker lock(client_lock);
+   tout(cct) << "fstatx flags " << hex << flags << " want " << want << dec << std::endl;
+   tout(cct) << fd << std::endl;
+   Fh *f = get_filehandle(fd);
+   if (!f)
+     return -EBADF;
+   unsigned mask = statx_to_mask(flags, want);
+   int r = 0;
+   if (mask && !f->inode->caps_issued_mask(mask)) {
 -    r = _getattr(f->inode, mask);
++    r = _getattr(f->inode, mask, perms);
+     if (r < 0) {
+       ldout(cct, 3) << "fstatx exit on error!" << dendl;
+       return r;
+     }
+   }
+   fill_statx(f->inode, mask, stx);
+   ldout(cct, 3) << "fstatx(" << fd << ", " << stx << ") = " << r << dendl;
+   return r;
+ }
  
  // not written yet, but i want to link!
  
@@@ -9550,7 -9771,7 +9772,7 @@@ int Client::ll_walk(const char* name, I
    tout(cct) << "ll_walk" << std::endl;
    tout(cct) << name << std::endl;
  
-   rc = path_walk(fp, &in, perms, false);
 -  rc = path_walk(fp, &in, false, CEPH_STAT_CAP_INODE_ALL);
++  rc = path_walk(fp, &in, perms, false, CEPH_STAT_CAP_INODE_ALL);
    if (rc < 0) {
      attr->st_ino = 0;
      *out = NULL;
@@@ -9669,30 -9890,51 +9891,51 @@@ Inode *Client::ll_get_inode(vinodeno_t 
    return in;
  }
  
- int Client::ll_getattr(Inode *in, struct stat *attr, const UserPerm& perms)
 -int Client::_ll_getattr(Inode *in, int uid, int gid)
++int Client::_ll_getattr(Inode *in, const UserPerm& perms)
  {
-   Mutex::Locker lock(client_lock);
    vinodeno_t vino = _get_vino(in);
  
    ldout(cct, 3) << "ll_getattr " << vino << dendl;
    tout(cct) << "ll_getattr" << std::endl;
    tout(cct) << vino.ino.val << std::endl;
  
-   int res;
    if (vino.snapid < CEPH_NOSNAP)
-     res = 0;
+     return 0;
    else
-     res = _getattr(in, CEPH_STAT_CAP_INODE_ALL, perms);
 -    return _getattr(in, CEPH_STAT_CAP_INODE_ALL, uid, gid);
++    return _getattr(in, CEPH_STAT_CAP_INODE_ALL, perms);
+ }
 -int Client::ll_getattr(Inode *in, struct stat *attr, int uid, int gid)
++int Client::ll_getattr(Inode *in, struct stat *attr, const UserPerm& perms)
+ {
+   Mutex::Locker lock(client_lock);
 -  int res = _ll_getattr(in, uid, gid);
++  int res = _ll_getattr(in, perms);
    if (res == 0)
      fill_stat(in, attr);
-   ldout(cct, 3) << "ll_getattr " << vino << " = " << res << dendl;
+   ldout(cct, 3) << "ll_getattr " << _get_vino(in) << " = " << res << dendl;
    return res;
  }
  
- int Client::ll_setattr(Inode *in, struct stat *attr, int mask,
-                      const UserPerm& perms)
+ int Client::ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want,
 -                      unsigned int flags, int uid, int gid)
++                      unsigned int flags, const UserPerm& perms)
+ {
+   Mutex::Locker lock(client_lock);
+   int res = 0;
+   unsigned mask = statx_to_mask(flags, want);
+   if (mask && !in->caps_issued_mask(mask))
 -    res = _ll_getattr(in, uid, gid);
++    res = _ll_getattr(in, perms);
+   if (res == 0)
+     fill_statx(in, mask, stx);
+   ldout(cct, 3) << "ll_getattrx " << _get_vino(in) << " = " << res << dendl;
+   return res;
+ }
  
 -int Client::_ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid,
 -                     int gid, InodeRef *inp)
++int Client::_ll_setattrx(Inode *in, struct ceph_statx *stx, int mask,
++                       const UserPerm& perms, InodeRef *inp)
  {
    Mutex::Locker lock(client_lock);
  
    tout(cct) << mask << std::endl;
  
    if (!cct->_conf->fuse_default_permissions) {
-     int res = may_setattr(in, attr, mask, perms);
 -    int res = may_setattr(in, stx, mask, uid, gid);
++    int res = may_setattr(in, stx, mask, perms);
      if (res < 0)
        return res;
    }
  
    mask &= ~(CEPH_SETATTR_MTIME_NOW | CEPH_SETATTR_ATIME_NOW);
  
 -  return __setattrx(in, stx, mask, uid, gid, inp);
++  return __setattrx(in, stx, mask, perms, inp);
+ }
 -int Client::ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid,
 -                     int gid)
++int Client::ll_setattrx(Inode *in, struct ceph_statx *stx, int mask,
++                      const UserPerm& perms)
+ {
    InodeRef target(in);
-   int res = _setattr(in, attr, mask, perms, &target);
 -  int res = _ll_setattrx(in, stx, mask, uid, gid, &target);
++  int res = _ll_setattrx(in, stx, mask, perms, &target);
+   if (res == 0) {
+     assert(in == target.get());
+     fill_statx(in, in->caps_issued(), stx);
+   }
+   ldout(cct, 3) << "ll_setattrx " << _get_vino(in) << " = " << res << dendl;
+   return res;
+ }
 -int Client::ll_setattr(Inode *in, struct stat *attr, int mask, int uid,
 -                     int gid)
++int Client::ll_setattr(Inode *in, struct stat *attr, int mask,
++                     const UserPerm& perms)
+ {
+   struct ceph_statx stx;
+   stat_to_statx(attr, &stx);
+   InodeRef target(in);
 -  int res = _ll_setattrx(in, &stx, mask, uid, gid, &target);
++  int res = _ll_setattrx(in, &stx, mask, perms, &target);
    if (res == 0) {
      assert(in == target.get());
      fill_stat(in, attr);
@@@ -9738,25 -10004,23 +10006,25 @@@ int Client::getxattr(const char *path, 
  {
    Mutex::Locker lock(client_lock);
    InodeRef in;
-   int r = Client::path_walk(path, &in, perms, true);
 -  int r = Client::path_walk(path, &in, true, CEPH_STAT_CAP_XATTR);
++  int r = Client::path_walk(path, &in, perms, true, CEPH_STAT_CAP_XATTR);
    if (r < 0)
      return r;
 -  return _getxattr(in, name, value, size);
 +  return _getxattr(in, name, value, size, perms);
  }
  
 -int Client::lgetxattr(const char *path, const char *name, void *value, size_t size)
 +int Client::lgetxattr(const char *path, const char *name, void *value, size_t size,
 +                    const UserPerm& perms)
  {
    Mutex::Locker lock(client_lock);
    InodeRef in;
-   int r = Client::path_walk(path, &in, perms, false);
 -  int r = Client::path_walk(path, &in, false, CEPH_STAT_CAP_XATTR);
++  int r = Client::path_walk(path, &in, perms, false, CEPH_STAT_CAP_XATTR);
    if (r < 0)
      return r;
 -  return _getxattr(in, name, value, size);
 +  return _getxattr(in, name, value, size, perms);
  }
  
 -int Client::fgetxattr(int fd, const char *name, void *value, size_t size)
 +int Client::fgetxattr(int fd, const char *name, void *value, size_t size,
 +                    const UserPerm& perms)
  {
    Mutex::Locker lock(client_lock);
    Fh *f = get_filehandle(fd);
@@@ -9770,24 -10033,23 +10038,24 @@@ int Client::listxattr(const char *path
  {
    Mutex::Locker lock(client_lock);
    InodeRef in;
-   int r = Client::path_walk(path, &in, perms, true);
 -  int r = Client::path_walk(path, &in, true, CEPH_STAT_CAP_XATTR);
++  int r = Client::path_walk(path, &in, perms, true, CEPH_STAT_CAP_XATTR);
    if (r < 0)
      return r;
 -  return Client::_listxattr(in.get(), list, size);
 +  return Client::_listxattr(in.get(), list, size, perms);
  }
  
 -int Client::llistxattr(const char *path, char *list, size_t size)
 +int Client::llistxattr(const char *path, char *list, size_t size,
 +                     const UserPerm& perms)
  {
    Mutex::Locker lock(client_lock);
    InodeRef in;
-   int r = Client::path_walk(path, &in, perms, false);
 -  int r = Client::path_walk(path, &in, false, CEPH_STAT_CAP_XATTR);
++  int r = Client::path_walk(path, &in, perms, false, CEPH_STAT_CAP_XATTR);
    if (r < 0)
      return r;
 -  return Client::_listxattr(in.get(), list, size);
 +  return Client::_listxattr(in.get(), list, size, perms);
  }
  
 -int Client::flistxattr(int fd, char *list, size_t size)
 +int Client::flistxattr(int fd, char *list, size_t size, const UserPerm& perms)
  {
    Mutex::Locker lock(client_lock);
    Fh *f = get_filehandle(fd);
@@@ -10061,9 -10316,9 +10329,9 @@@ int Client::_setxattr(Inode *in, const 
          size = 0;
        }
        if (new_mode != in->mode) {
-         struct stat attr;
-         attr.st_mode = new_mode;
-         ret = _do_setattr(in, &attr, CEPH_SETATTR_MODE, perms, NULL);
+         struct ceph_statx stx;
+         stx.stx_mode = new_mode;
 -        ret = _do_setattr(in, &stx, CEPH_SETATTR_MODE, uid, gid, NULL);
++        ret = _do_setattr(in, &stx, CEPH_SETATTR_MODE, perms, NULL);
          if (ret < 0)
            return ret;
        }
@@@ -11341,8 -11596,10 +11609,10 @@@ int Client::ll_open(Inode *in, int flag
  
  int Client::ll_create(Inode *parent, const char *name, mode_t mode,
                      int flags, struct stat *attr, Inode **outp, Fh **fhp,
 -                    int uid, int gid)
 +                    const UserPerm& perms)
  {
+   *fhp = NULL;
    Mutex::Locker lock(client_lock);
  
    vinodeno_t vparent = _get_vino(parent);
        if (r < 0)
        goto out;
      }
-     r = _create(parent, name, flags, mode, &in, fhp /* may be NULL */,
-               0, 0, 0, NULL, &created, perms);
+     r = _create(parent, name, flags, mode, &in, fhp, 0, 0, 0, NULL, &created,
 -              uid, gid);
++              perms);
      if (r < 0)
        goto out;
    }
    ldout(cct, 20) << "ll_create created = " << created << dendl;
    if (!created) {
      if (!cct->_conf->fuse_default_permissions) {
 -      r = may_open(in.get(), flags, uid, gid);
 +      r = may_open(in.get(), flags, perms);
        if (r < 0) {
-       if (fhp && *fhp) {
+       if (*fhp) {
          int release_r = _release_fh(*fhp);
          assert(release_r == 0);  // during create, no async data ops should have happened
        }
        goto out;
        }
      }
-     if (fhp && (*fhp == NULL)) {
+     if (*fhp == NULL) {
 -      r = _open(in.get(), flags, mode, fhp, uid, gid);
 +      r = _open(in.get(), flags, mode, fhp, perms);
        if (r < 0)
        goto out;
      }
@@@ -11722,9 -11978,10 +11993,10 @@@ int Client::_fallocate(Fh *fh, int mode
      if (size > in->size) {
        in->size = size;
        in->mtime = ceph_clock_now(cct);
+       in->change_attr++;
        mark_caps_dirty(in, CEPH_CAP_FILE_WR);
  
 -      if (is_quota_bytes_approaching(in)) {
 +      if (is_quota_bytes_approaching(in, fh->actor_perms)) {
          check_caps(in, true);
        } else {
          if ((in->size << 1) >= in->max_size &&
index 23e623b74569902223f1c95af8765a2cebc1aa83,9c1bf4dfdd0824ea863c237928c00f4b2b983711..75a35d21e0f4d9060d5275f5ca2cc6c553037b66
@@@ -516,8 -518,8 +516,9 @@@ protected
  
    // path traversal for high-level interface
    InodeRef cwd;
 -  int path_walk(const filepath& fp, InodeRef *end, bool followsym=true,
 -              int mask=0, int uid=-1, int gid=-1);
 +  int path_walk(const filepath& fp, InodeRef *end, const UserPerm& perms,
-               bool followsym=true);
++              bool followsym=true, int mask=0, int uid=-1, int gid=-1);
++              
    int fill_stat(Inode *in, struct stat *st, frag_info_t *dirstat=0, nest_info_t *rstat=0);
    int fill_stat(InodeRef& in, struct stat *st, frag_info_t *dirstat=0, nest_info_t *rstat=0) {
      return fill_stat(in.get(), st, dirstat, rstat);
    void clear_dir_complete_and_ordered(Inode *diri, bool complete);
    void insert_readdir_results(MetaRequest *request, MetaSession *session, Inode *diri);
    Inode* insert_trace(MetaRequest *request, MetaSession *session);
-   void update_inode_file_bits(Inode *in,
-                             uint64_t truncate_seq, uint64_t truncate_size, uint64_t size,
-                             uint64_t time_warp_seq, utime_t ctime, utime_t mtime, utime_t atime,
-                             version_t inline_version, bufferlist& inline_data,
-                             int issued);
+   void update_inode_file_bits(Inode *in, uint64_t truncate_seq, uint64_t truncate_size, uint64_t size,
+                             uint64_t change_attr, uint64_t time_warp_seq, utime_t ctime,
+                             utime_t mtime, utime_t atime, version_t inline_version,
+                             bufferlist& inline_data, int issued);
 -  Inode *add_update_inode(InodeStat *st, utime_t ttl, MetaSession *session);
 +  Inode *add_update_inode(InodeStat *st, utime_t ttl, MetaSession *session,
 +                        const UserPerm& request_perms);
    Dentry *insert_dentry_inode(Dir *dir, const string& dname, LeaseStat *dlease, 
                              Inode *in, utime_t from, MetaSession *session,
                              Dentry *old_dentry = NULL);
@@@ -749,56 -756,43 +756,61 @@@ private
  
    // internal interface
    //   call these with client_lock held!
 -  int _do_lookup(Inode *dir, const string& name, int mask, InodeRef *target, int uid, int gid);
 -  int _lookup(Inode *dir, const string& dname, int mask, InodeRef *target, int uid, int gid);
 -
 -  int _link(Inode *in, Inode *dir, const char *name, int uid=-1, int gid=-1, InodeRef *inp = 0);
 -  int _unlink(Inode *dir, const char *name, int uid=-1, int gid=-1);
 -  int _rename(Inode *olddir, const char *oname, Inode *ndir, const char *nname, int uid=-1, int gid=-1);
 -  int _mkdir(Inode *dir, const char *name, mode_t mode, int uid=-1, int gid=-1, InodeRef *inp = 0);
 -  int _rmdir(Inode *dir, const char *name, int uid=-1, int gid=-1);
 -  int _symlink(Inode *dir, const char *name, const char *target, int uid=-1, int gid=-1, InodeRef *inp = 0);
 -  int _mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, int uid=-1, int gid=-1, InodeRef *inp = 0);
 -  int _do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid, InodeRef *inp);
 +  int _do_lookup(Inode *dir, const string& name, int mask, InodeRef *target,
 +               const UserPerm& perms);
 +
 +  int _lookup(Inode *dir, const string& dname, int mask, InodeRef *target,
 +            const UserPerm& perm);
 +
 +  int _link(Inode *in, Inode *dir, const char *name, const UserPerm& perm,
 +          InodeRef *inp = 0);
 +  int _unlink(Inode *dir, const char *name, const UserPerm& perm);
 +  int _rename(Inode *olddir, const char *oname, Inode *ndir, const char *nname, const UserPerm& perm);
 +  int _mkdir(Inode *dir, const char *name, mode_t mode, const UserPerm& perm,
 +           InodeRef *inp = 0);
 +  int _rmdir(Inode *dir, const char *name, const UserPerm& perms);
 +  int _symlink(Inode *dir, const char *name, const char *target,
 +             const UserPerm& perms, InodeRef *inp = 0);
 +  int _mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev,
 +           const UserPerm& perms, InodeRef *inp = 0);
-   int _do_setattr(Inode *in, struct stat *attr, int mask, const UserPerm& perms,
-                 InodeRef *inp);
-   int _setattr(Inode *in, struct stat *attr, int mask, const UserPerm& perms,
-              InodeRef *inp = 0);
++  int _do_setattr(Inode *in, struct ceph_statx *stx, int mask,
++                const UserPerm& perms, InodeRef *inp);
+   void stat_to_statx(struct stat *st, struct ceph_statx *stx);
 -  int __setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid=-1, int gid=-1, InodeRef *inp = 0);
 -  int _setattrx(InodeRef &in, struct ceph_statx *stx, int mask);
 -  int _setattr(InodeRef &in, struct stat *attr, int mask);
 -  int _ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid = -1,
 -               int gid = -1, InodeRef *inp = 0);
 -  int _getattr(Inode *in, int mask, int uid=-1, int gid=-1, bool force=false);
 -  int _getattr(InodeRef &in, int mask, int uid=-1, int gid=-1, bool force=false) {
 -    return _getattr(in.get(), mask, uid, gid, force);
++  int __setattrx(Inode *in, struct ceph_statx *stx, int mask,
++               const UserPerm& perms, InodeRef *inp = 0);
++  int _setattrx(InodeRef &in, struct ceph_statx *stx, int mask,
++              const UserPerm& perms);
 +  int _setattr(InodeRef &in, struct stat *attr, int mask,
 +             const UserPerm& perms);
++  int _ll_setattrx(Inode *in, struct ceph_statx *stx, int mask,
++                 const UserPerm& perms, InodeRef *inp = 0);
 +  int _getattr(Inode *in, int mask, const UserPerm& perms, bool force=false);
 +  int _getattr(InodeRef &in, int mask, const UserPerm& perms, bool force=false) {
 +    return _getattr(in.get(), mask, perms, force);
    }
    int _readlink(Inode *in, char *buf, size_t size);
 -  int _getxattr(Inode *in, const char *name, void *value, size_t len, int uid=-1, int gid=-1);
 -  int _getxattr(InodeRef &in, const char *name, void *value, size_t len);
 -  int _listxattr(Inode *in, char *names, size_t len, int uid=-1, int gid=-1);
 -  int _do_setxattr(Inode *in, const char *name, const void *value, size_t len, int flags, int uid, int gid);
 -  int _setxattr(Inode *in, const char *name, const void *value, size_t len, int flags, int uid=-1, int gid=-1);
 -  int _setxattr(InodeRef &in, const char *name, const void *value, size_t len, int flags);
 -  int _removexattr(Inode *in, const char *nm, int uid=-1, int gid=-1);
 -  int _removexattr(InodeRef &in, const char *nm);
 -  int _open(Inode *in, int flags, mode_t mode, Fh **fhp, int uid, int gid);
 +  int _getxattr(Inode *in, const char *name, void *value, size_t len,
 +              const UserPerm& perms);
 +  int _getxattr(InodeRef &in, const char *name, void *value, size_t len,
 +              const UserPerm& perms);
 +  int _listxattr(Inode *in, char *names, size_t len, const UserPerm& perms);
 +  int _do_setxattr(Inode *in, const char *name, const void *value, size_t len,
 +                 int flags, const UserPerm& perms);
 +  int _setxattr(Inode *in, const char *name, const void *value, size_t len,
 +              int flags, const UserPerm& perms);
 +  int _setxattr(InodeRef &in, const char *name, const void *value, size_t len,
 +              int flags, const UserPerm& perms);
 +  int _removexattr(Inode *in, const char *nm, const UserPerm& perms);
 +  int _removexattr(InodeRef &in, const char *nm, const UserPerm& perms);
 +  int _open(Inode *in, int flags, mode_t mode, Fh **fhp,
 +          const UserPerm& perms);
    int _renew_caps(Inode *in);
 -  int _create(Inode *in, const char *name, int flags, mode_t mode, InodeRef *inp, Fh **fhp,
 -              int stripe_unit, int stripe_count, int object_size, const char *data_pool,
 -            bool *created, int uid, int gid);
 +  int _create(Inode *in, const char *name, int flags, mode_t mode, InodeRef *inp,
 +            Fh **fhp, int stripe_unit, int stripe_count, int object_size,
 +            const char *data_pool, bool *created, const UserPerm &perms);
  
    loff_t _lseek(Fh *fh, loff_t offset, int whence);
 +  loff_t _lseek(Fh *fh, loff_t offset, int whence, const UserPerm& perms);
    int _read(Fh *fh, int64_t offset, uint64_t size, bufferlist *bl);
    int _write(Fh *fh, int64_t offset, uint64_t size, const char *buf,
            const struct iovec *iov, int iovcnt);
      MAY_READ = 4,
    };
  
 -  class RequestUserGroups : public UserGroups {
 -    Client *client;
 -    uid_t uid;
 -    gid_t gid;
 -    int sgid_count;
 -    gid_t *sgids;
 -    void init() {
 -      sgid_count = client->_getgrouplist(&sgids, uid, gid);
 -    }
 -    public:
 -    RequestUserGroups(Client *c, uid_t u, gid_t g) :
 -      client(c), uid(u), gid(g), sgid_count(-1), sgids(NULL) {}
 -    ~RequestUserGroups() {
 -      free(sgids);
 -    }
 -    gid_t get_gid() { return gid; }
 -    bool is_in(gid_t id);
 -    int get_gids(const gid_t **out);
 -  };
 +  void init_groups(UserPerm *groups);
 +
 +  int inode_permission(Inode *in, const UserPerm& perms, unsigned want);
 +  int xattr_permission(Inode *in, const char *name, unsigned want,
 +                     const UserPerm& perms);
-   int may_setattr(Inode *in, struct stat *st, int mask, const UserPerm& perms);
++  int may_setattr(Inode *in, struct ceph_statx *stx, int mask,
++                const UserPerm& perms);
 +  int may_open(Inode *in, int flags, const UserPerm& perms);
 +  int may_lookup(Inode *dir, const UserPerm& perms);
 +  int may_create(Inode *dir, const UserPerm& perms);
 +  int may_delete(Inode *dir, const char *name, const UserPerm& perms);
 +  int may_hardlink(Inode *in, const UserPerm& perms);
  
 -  int inode_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want);
 -  int xattr_permission(Inode *in, const char *name, unsigned want, int uid=-1, int gid=-1);
 -  int may_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid=-1, int gid=-1);
 -  int may_open(Inode *in, int flags, int uid=-1, int gid=-1);
 -  int may_lookup(Inode *dir, int uid=-1, int gid=-1);
 -  int may_create(Inode *dir, int uid=-1, int gid=-1);
 -  int may_delete(Inode *dir, const char *name, int uid=-1, int gid=-1);
 -  int may_hardlink(Inode *in, int uid=-1, int gid=-1);
 -  int _getattr_for_perm(Inode *in, int uid, int gid);
 -  int _getgrouplist(gid_t **sgids, int uid, int gid);
 +  int _getattr_for_perm(Inode *in, const UserPerm& perms);
 +  int _getgrouplist(gid_t **sgids, uid_t uid, gid_t gid);
  
    int check_data_pool_exist(string name, string value, const OSDMap *osdmap);
  
  
    mds_rank_t _get_random_up_mds() const;
  
 -  int _ll_getattr(Inode *in, int uid, int gid);
++  int _ll_getattr(Inode *in, const UserPerm& perms);
  public:
 -  int mount(const std::string &mount_root, bool require_mds=false);
 +  int mount(const std::string &mount_root, const UserPerm& perms,
 +          bool require_mds=false);
    void unmount();
  
    int mds_command(
    loff_t telldir(dir_result_t *dirp);
    void seekdir(dir_result_t *dirp, loff_t offset);
  
 -  int link(const char *existing, const char *newname);
 -  int unlink(const char *path);
 -  int rename(const char *from, const char *to);
 +  int link(const char *existing, const char *newname, const UserPerm& perm);
 +  int unlink(const char *path, const UserPerm& perm);
 +  int rename(const char *from, const char *to, const UserPerm& perm);
  
    // dirs
 -  int mkdir(const char *path, mode_t mode);
 -  int mkdirs(const char *path, mode_t mode);
 -  int rmdir(const char *path);
 +  int mkdir(const char *path, mode_t mode, const UserPerm& perm);
 +  int mkdirs(const char *path, mode_t mode, const UserPerm& perms);
 +  int rmdir(const char *path, const UserPerm& perms);
  
    // symlinks
 -  int readlink(const char *path, char *buf, loff_t size);
 +  int readlink(const char *path, char *buf, loff_t size, const UserPerm& perms);
  
 -  int symlink(const char *existing, const char *newname);
 +  int symlink(const char *existing, const char *newname, const UserPerm& perms);
  
    // inode stuff
 -  int stat(const char *path, struct stat *stbuf, frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL);
 -  int statx(const char *path, struct ceph_statx *stx, unsigned int want, unsigned int flags);
 -  int lstat(const char *path, struct stat *stbuf, frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL);
 -  int lstatlite(const char *path, struct statlite *buf);
 -
 -  int setattr(const char *relpath, struct stat *attr, int mask);
 -  int setattrx(const char *relpath, struct ceph_statx *stx, int mask, int flags=0);
 -  int fsetattr(int fd, struct stat *attr, int mask);
 -  int chmod(const char *path, mode_t mode);
 -  int fchmod(int fd, mode_t mode);
 -  int lchmod(const char *path, mode_t mode);
 -  int chown(const char *path, int uid, int gid);
 -  int fchown(int fd, int uid, int gid);
 -  int lchown(const char *path, int uid, int gid);
 -  int utime(const char *path, struct utimbuf *buf);
 -  int lutime(const char *path, struct utimbuf *buf);
+   unsigned statx_to_mask(unsigned int flags, unsigned int want);
-   int setattr(const char *relpath, struct stat *attr, int mask, const UserPerm& perms);
 +  int stat(const char *path, struct stat *stbuf, const UserPerm& perms,
 +         frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL);
++  int statx(const char *path, struct ceph_statx *stx,
++          const UserPerm& perms,
++          unsigned int want, unsigned int flags);
 +  int lstat(const char *path, struct stat *stbuf, const UserPerm& perms,
 +          frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL);
 +
++  int setattr(const char *relpath, struct stat *attr, int mask,
++            const UserPerm& perms);
++  int setattrx(const char *relpath, struct ceph_statx *stx, int mask,
++             const UserPerm& perms, int flags=0);
 +  int fsetattr(int fd, struct stat *attr, int mask, const UserPerm& perms);
 +  int chmod(const char *path, mode_t mode, const UserPerm& perms);
 +  int fchmod(int fd, mode_t mode, const UserPerm& perms);
 +  int lchmod(const char *path, mode_t mode, const UserPerm& perms);
 +  int chown(const char *path, uid_t new_uid, gid_t new_gid,
 +          const UserPerm& perms);
 +  int fchown(int fd, uid_t new_uid, gid_t new_gid, const UserPerm& perms);
 +  int lchown(const char *path, uid_t new_uid, gid_t new_gid,
 +           const UserPerm& perms);
 +  int utime(const char *path, struct utimbuf *buf, const UserPerm& perms);
 +  int lutime(const char *path, struct utimbuf *buf, const UserPerm& perms);
    int flock(int fd, int operation, uint64_t owner);
 -  int truncate(const char *path, loff_t size);
 +  int truncate(const char *path, loff_t size, const UserPerm& perms);
  
    // file ops
 -  int mknod(const char *path, mode_t mode, dev_t rdev=0);
 -  int open(const char *path, int flags, mode_t mode=0);
 -  int open(const char *path, int flags, mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool);
 -  int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name);
 -  int lookup_ino(inodeno_t ino, Inode **inode=NULL);
 -  int lookup_parent(Inode *in, Inode **parent=NULL);
 -  int lookup_name(Inode *in, Inode *parent);
 +  int mknod(const char *path, mode_t mode, const UserPerm& perms, dev_t rdev=0);
 +  int open(const char *path, int flags, const UserPerm& perms, mode_t mode=0);
 +  int open(const char *path, int flags, const UserPerm& perms,
 +         mode_t mode, int stripe_unit, int stripe_count, int object_size,
 +         const char *data_pool);
 +  int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name,
 +                const UserPerm& perms);
 +  int lookup_ino(inodeno_t ino, const UserPerm& perms, Inode **inode=NULL);
 +  int lookup_parent(Inode *in, const UserPerm& perms, Inode **parent=NULL);
 +  int lookup_name(Inode *in, Inode *parent, const UserPerm& perms);
    int close(int fd);
 -  loff_t lseek(int fd, loff_t offset, int whence);
 +  loff_t lseek(int fd, loff_t offset, int whence, const UserPerm& perms);
    int read(int fd, char *buf, loff_t size, loff_t offset=-1);
    int preadv(int fd, const struct iovec *iov, int iovcnt, loff_t offset=-1);
    int write(int fd, const char *buf, loff_t size, loff_t offset=-1);
    int pwritev(int fd, const struct iovec *iov, int iovcnt, loff_t offset=-1);
    int fake_write_size(int fd, loff_t size);
 -  int ftruncate(int fd, loff_t size);
 +  int ftruncate(int fd, loff_t size, const UserPerm& perms);
    int fsync(int fd, bool syncdataonly);
 -  int fstat(int fd, struct stat *stbuf, int mask=CEPH_STAT_CAP_INODE_ALL);
 -  int fstatx(int fd, struct ceph_statx *stx, unsigned int want, unsigned int flags);
 +  int fstat(int fd, struct stat *stbuf, const UserPerm& perms,
 +          int mask=CEPH_STAT_CAP_INODE_ALL);
++  int fstatx(int fd, struct ceph_statx *stx, const UserPerm& perms,
++           unsigned int want, unsigned int flags);
    int fallocate(int fd, int mode, loff_t offset, loff_t length);
  
    // full path xattr ops
    Inode *ll_get_inode(ino_t ino);
    Inode *ll_get_inode(vinodeno_t vino);
    int ll_lookup(Inode *parent, const char *name, struct stat *attr,
 -              Inode **out, int uid = -1, int gid = -1);
 +              Inode **out, const UserPerm& perms);
    bool ll_forget(Inode *in, int count);
    bool ll_put(Inode *in);
 -  int ll_getattr(Inode *in, struct stat *st, int uid = -1, int gid = -1);
 +  int ll_getattr(Inode *in, struct stat *st, const UserPerm& perms);
-   int ll_setattr(Inode *in, struct stat *st, int mask, const UserPerm& perms);
+   int ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want,
 -                unsigned int flags, int uid = -1, int gid = -1);
 -  int ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid = -1,
 -               int gid = -1);
 -  int ll_setattr(Inode *in, struct stat *st, int mask, int uid = -1,
 -               int gid = -1);
++                unsigned int flags, const UserPerm& perms);
++  int ll_setattrx(Inode *in, struct ceph_statx *stx, int mask,
++                const UserPerm& perms);
++  int ll_setattr(Inode *in, struct stat *st, int mask,
++               const UserPerm& perms);
    int ll_getxattr(Inode *in, const char *name, void *value, size_t size,
 -                int uid=-1, int gid=-1);
 +                const UserPerm& perms);
    int ll_setxattr(Inode *in, const char *name, const void *value, size_t size,
 -                int flags, int uid=-1, int gid=-1);
 -  int ll_removexattr(Inode *in, const char *name, int uid=-1, int gid=-1);
 -  int ll_listxattr(Inode *in, char *list, size_t size, int uid=-1, int gid=-1);
 -  int ll_opendir(Inode *in, int flags, dir_result_t **dirpp, int uid = -1, int gid = -1);
 +                int flags, const UserPerm& perms);
 +  int ll_removexattr(Inode *in, const char *name, const UserPerm& perms);
 +  int ll_listxattr(Inode *in, char *list, size_t size, const UserPerm& perms);
 +  int ll_opendir(Inode *in, int flags, dir_result_t **dirpp,
 +               const UserPerm& perms);
    int ll_releasedir(dir_result_t* dirp);
    int ll_fsyncdir(dir_result_t* dirp);
 -  int ll_readlink(Inode *in, char *buf, size_t bufsize, int uid = -1, int gid = -1);
 +  int ll_readlink(Inode *in, char *buf, size_t bufsize, const UserPerm& perms);
    int ll_mknod(Inode *in, const char *name, mode_t mode, dev_t rdev,
 -             struct stat *attr, Inode **out, int uid = -1, int gid = -1);
 +             struct stat *attr, Inode **out, const UserPerm& perms);
    int ll_mkdir(Inode *in, const char *name, mode_t mode, struct stat *attr,
 -             Inode **out, int uid = -1, int gid = -1);
 +             Inode **out, const UserPerm& perm);
    int ll_symlink(Inode *in, const char *name, const char *value,
 -               struct stat *attr, Inode **out, int uid = -1, int gid = -1);
 -  int ll_unlink(Inode *in, const char *name, int uid = -1, int gid = -1);
 -  int ll_rmdir(Inode *in, const char *name, int uid = -1, int gid = -1);
 +               struct stat *attr, Inode **out, const UserPerm& perms);
 +  int ll_unlink(Inode *in, const char *name, const UserPerm& perm);
 +  int ll_rmdir(Inode *in, const char *name, const UserPerm& perms);
    int ll_rename(Inode *parent, const char *name, Inode *newparent,
 -              const char *newname, int uid = -1, int gid = -1);
 +              const char *newname, const UserPerm& perm);
    int ll_link(Inode *in, Inode *newparent, const char *newname,
 -            struct stat *attr, int uid = -1, int gid = -1);
 -  int ll_open(Inode *in, int flags, Fh **fh, int uid = -1, int gid = -1);
 +            struct stat *attr, const UserPerm& perm);
 +  int ll_open(Inode *in, int flags, Fh **fh, const UserPerm& perms);
    int ll_create(Inode *parent, const char *name, mode_t mode, int flags,
 -              struct stat *attr, Inode **out, Fh **fhp, int uid = -1,
 -              int gid = -1);
 +              struct stat *attr, Inode **out, Fh **fhp,
 +              const UserPerm& perms);
    int ll_read_block(Inode *in, uint64_t blockid, char *buf,  uint64_t offset,
                    uint64_t length, file_layout_t* layout);
  
Simple merge
Simple merge
Simple merge
Simple merge
index c38cbcf78e0ddaa60c753b885518aa6f4710a4f0,9e65bff95d298757c979c09c821f878eac66dbc7..f24ff945fe4dfd17d2aa5263dc5a6f1c98321213
@@@ -610,9 -607,17 +610,18 @@@ extern "C" int ceph_stat(struct ceph_mo
  {
    if (!cmount->is_mounted())
      return -ENOTCONN;
 -  return cmount->get_client()->stat(path, stbuf);
 +  return cmount->get_client()->stat(path, stbuf, cmount->default_perms);
  }
  
 -  return cmount->get_client()->statx(path, stx, want, flags);
+ extern "C" int ceph_statx(struct ceph_mount_info *cmount, const char *path,
+                         struct ceph_statx *stx, unsigned int want, unsigned int flags)
+ {
+   if (!cmount->is_mounted())
+     return -ENOTCONN;
++  return cmount->get_client()->statx(path, stx, cmount->default_perms,
++                                   want, flags);
+ }
  extern "C" int ceph_lstat(struct ceph_mount_info *cmount, const char *path,
                          struct stat *stbuf)
  {
@@@ -626,9 -631,17 +635,18 @@@ extern "C" int ceph_setattr(struct ceph
  {
    if (!cmount->is_mounted())
      return -ENOTCONN;
 -  return cmount->get_client()->setattr(relpath, attr, mask);
 +  return cmount->get_client()->setattr(relpath, attr, mask, cmount->default_perms);
  }
  
 -  return cmount->get_client()->setattrx(relpath, stx, mask, flags);
+ extern "C" int ceph_setattrx(struct ceph_mount_info *cmount, const char *relpath,
+                           struct ceph_statx *stx, int mask, int flags)
+ {
+   if (!cmount->is_mounted())
+     return -ENOTCONN;
++  return cmount->get_client()->setattrx(relpath, stx, mask,
++                                      cmount->default_perms, flags);
+ }
  // *xattr() calls supporting samba/vfs
  extern "C" int ceph_getxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size)
  {
@@@ -876,9 -887,17 +894,18 @@@ extern "C" int ceph_fstat(struct ceph_m
  {
    if (!cmount->is_mounted())
      return -ENOTCONN;
 -  return cmount->get_client()->fstat(fd, stbuf);
 +  return cmount->get_client()->fstat(fd, stbuf, cmount->default_perms);
  }
  
 -  return cmount->get_client()->fstatx(fd, stx, want, flags);
+ extern "C" int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_statx *stx,
+                           unsigned int want, unsigned int flags)
+ {
+   if (!cmount->is_mounted())
+     return -ENOTCONN;
++  return cmount->get_client()->fstatx(fd, stx, cmount->default_perms,
++                                    want, flags);
+ }
  extern "C" int ceph_sync_fs(struct ceph_mount_info *cmount)
  {
    if (!cmount->is_mounted())
@@@ -1411,18 -1427,31 +1438,35 @@@ extern "C" int ceph_ll_getattr(class ce
                               Inode *in, struct stat *attr,
                               int uid, int gid)
  {
 -  return (cmount->get_client()->ll_getattr(in, attr, uid, gid));
 +  UserPerm perms(uid, gid);
 +  return (cmount->get_client()->ll_getattr(in, attr, perms));
  }
  
 -  return (cmount->get_client()->ll_getattrx(in, stx, want, flags, uid, gid));
+ extern "C" int ceph_ll_getattrx(class ceph_mount_info *cmount,
+                               Inode *in, struct ceph_statx *stx,
+                               unsigned int want, unsigned int flags,
+                               int uid, int gid)
+ {
++  UserPerm perms(uid, gid);
++  return (cmount->get_client()->ll_getattrx(in, stx, want, flags, perms));
+ }
  extern "C" int ceph_ll_setattr(class ceph_mount_info *cmount,
                               Inode *in, struct stat *st,
                               int mask, int uid, int gid)
  {
 -  return (cmount->get_client()->ll_setattr(in, st, mask, uid, gid));
 +  UserPerm perms(uid, gid);
 +  return (cmount->get_client()->ll_setattr(in, st, mask, perms));
  }
  
 -  return (cmount->get_client()->ll_setattrx(in, stx, mask, uid, gid));
+ extern "C" int ceph_ll_setattrx(class ceph_mount_info *cmount,
+                              Inode *in, struct ceph_statx *stx,
+                              int mask, int uid, int gid)
+ {
++  UserPerm perms(uid, gid);
++  return (cmount->get_client()->ll_setattrx(in, stx, mask, perms));
+ }
  extern "C" int ceph_ll_open(class ceph_mount_info *cmount, Inode *in,
                            int flags, Fh **fh, int uid, int gid)
  {
Simple merge
Simple merge
Simple merge
Simple merge