]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: xattr ops, fuse hooks
authorSage Weil <sage@newdream.net>
Sun, 18 May 2008 16:51:42 +0000 (09:51 -0700)
committerSage Weil <sage@newdream.net>
Mon, 19 May 2008 16:06:22 +0000 (09:06 -0700)
src/client/Client.cc
src/client/Client.h
src/client/fuse_ll.cc
src/include/ceph_fs.h
src/kernel/mds_client.c
src/messages/MClientRequest.h

index 368887edf6b2146c6e42cf3036fd2a7eeb79f25f..dc5449a9d7331b0724a07aa053f9ed50f8310329 100644 (file)
@@ -381,6 +381,7 @@ void Client::update_inode(Inode *in, InodeStat *st, LeaseStat *lease, utime_t fr
     in->inode.anchored = false;  /* lie */
 
     in->dirfragtree = st->dirfragtree;  // FIXME look at the mask!
+    in->xattrs = st->xattrs;
 
     in->inode.ctime = st->ctime;
     in->inode.max_size = st->max_size;  // right?
@@ -3744,6 +3745,158 @@ int Client::ll_setattr(inodeno_t ino, struct stat *attr, int mask, int uid, int
   return 0;
 }
 
+// ----------
+// xattrs
+
+int Client::ll_getxattr(inodeno_t ino, const char *name, void *value, size_t size, int uid, int gid)
+{
+  Mutex::Locker lock(client_lock);
+  dout(3) << "ll_getxattr " << ino << " " << name << " size " << size << dendl;
+  tout << "ll_getxattr" << std::endl;
+  tout << ino.val << std::endl;
+  tout << name << std::endl;
+
+  Inode *in = _ll_get_inode(ino);
+  filepath path;
+  in->make_path(path);
+  return _getxattr(path, name, value, size, false, uid, gid);
+}
+
+int Client::_getxattr(const filepath &path, const char *name, void *value, size_t size,
+                     bool followsym, int uid, int gid)
+{
+  Inode *in = 0;
+  int r = _do_lstat(path, CEPH_STAT_MASK_XATTR, &in, uid, gid);
+  if (r == 0) {
+    string n(name);
+    r = -ENOENT;
+    if (in->xattrs.count(n)) {
+      r = in->xattrs[n].length();
+      if (size != 0) {
+       if (size >= (unsigned)r)
+         memcpy(value, in->xattrs[n].c_str(), r);
+       else
+         r = -ERANGE;
+      }
+    }
+  }
+  dout(3) << "_setxattr(\"" << path << "\", \"" << name << "\", " << size << ") = " << r << dendl;
+  return r;
+}
+
+int Client::ll_listxattr(inodeno_t ino, char *names, size_t size, int uid, int gid)
+{
+  Mutex::Locker lock(client_lock);
+  dout(3) << "ll_listxattr " << ino << " size " << size << dendl;
+  tout << "ll_listxattr" << std::endl;
+  tout << ino.val << std::endl;
+  tout << size << std::endl;
+
+  Inode *in = _ll_get_inode(ino);
+  filepath path;
+  in->make_path(path);
+  return _listxattr(path, names, size, false, uid, gid);
+}
+
+int Client::_listxattr(const filepath &path, char *name, size_t size,
+                      bool followsym, int uid, int gid)
+{
+  Inode *in = 0;
+  int r = _do_lstat(path, CEPH_STAT_MASK_XATTR, &in, uid, gid);
+  if (r == 0) {
+    for (map<string,bufferptr>::iterator p = in->xattrs.begin();
+        p != in->xattrs.end();
+        p++)
+      r += p->second.length() + 1;
+    
+    if (size != 0) {
+      if (size >= (unsigned)r) {
+       for (map<string,bufferptr>::iterator p = in->xattrs.begin();
+            p != in->xattrs.end();
+            p++) {
+         memcpy(name, p->second.c_str(), p->second.length());
+         name += p->second.length();
+         *name = '\0';
+         name++;
+       }
+      } else
+       r = -ERANGE;
+    }
+  }
+  dout(3) << "_listxattr(\"" << path << "\", " << size << ") = " << r << dendl;
+  return r;
+}
+
+int Client::ll_setxattr(inodeno_t ino, const char *name, const void *value, size_t size, int flags, int uid, int gid)
+{
+  Mutex::Locker lock(client_lock);
+  dout(3) << "ll_setxattr " << ino << " " << name << " size " << size << dendl;
+  tout << "ll_setxattr" << std::endl;
+  tout << ino.val << std::endl;
+  tout << name << std::endl;
+
+  Inode *in = _ll_get_inode(ino);
+  if (in->dn) touch_dn(in->dn);
+
+  filepath path;
+  in->make_path(path);
+  return _setxattr(path, name, value, size, flags, false, uid, gid);
+}
+
+int Client::_setxattr(const filepath &path, const char *name, const void *value, size_t size, int flags,
+                     bool followsym, int uid, int gid)
+{
+  MClientRequest *req = new MClientRequest(CEPH_MDS_OP_LSETXATTR, messenger->get_myinst());
+  req->set_filepath(path);
+  req->set_path2(name);
+  req->head.args.setxattr.flags = flags;
+
+  bufferlist bl;
+  bl.append((const char*)value, size);
+  req->set_data(bl);
+  
+  MClientReply *reply = make_request(req, uid, gid);
+  int res = reply->get_result();
+  delete reply;
+
+  trim_cache();
+  dout(3) << "_setxattr(\"" << path << "\", \"" << name << "\") = " << res << dendl;
+  return res;
+}
+
+int Client::ll_removexattr(inodeno_t ino, const char *name, int uid, int gid)
+{
+  Mutex::Locker lock(client_lock);
+  dout(3) << "ll_removexattr " << ino << " " << name << dendl;
+  tout << "ll_removexattr" << std::endl;
+  tout << ino.val << std::endl;
+  tout << name << std::endl;
+
+  Inode *in = _ll_get_inode(ino);
+  if (in->dn) touch_dn(in->dn);
+
+  filepath path;
+  in->make_path(path);
+  return _removexattr(path, name, false, uid, gid);
+}
+
+int Client::_removexattr(const filepath &path, const char *name, 
+                        bool followsym, int uid, int gid)
+{
+  MClientRequest *req = new MClientRequest(CEPH_MDS_OP_LRMXATTR, messenger->get_myinst());
+  req->set_filepath(path);
+  MClientReply *reply = make_request(req, uid, gid);
+  int res = reply->get_result();
+  delete reply;
+
+  trim_cache();
+  dout(3) << "_removexattr(\"" << path << "\", \"" << name << "\") = " << res << dendl;
+  return res;
+}
+
+
+
 int Client::ll_readlink(inodeno_t ino, const char **value, int uid, int gid)
 {
   Mutex::Locker lock(client_lock);
index d93df8258edb5730b1b1f21fd4323e4d271bd778..5e640a2bd05b4d128c495dda72077d7fcf6891f3 100644 (file)
@@ -161,6 +161,7 @@ class Inode {
   Dentry    *dn;      // if i'm linked to a dentry.
   string    *symlink; // symlink content, if it's a symlink
   fragtree_t dirfragtree;
+  map<string,bufferptr> xattrs;
   map<frag_t,int> fragmap;  // known frag -> mds mappings
 
   list<Cond*>       waitfor_caps;
@@ -810,6 +811,10 @@ private:
   int _lstat(const filepath &path, struct stat *stbuf, int uid=-1, int gid=-1);
   int _chmod(const filepath &path, mode_t mode, bool followsym, int uid=-1, int gid=-1);
   int _chown(const filepath &path, uid_t uid, gid_t gid, bool followsym, int cuid=-1, int cgid=-1);
+  int _getxattr(const filepath &path, const char *name, void *value, size_t len, bool followsym, int uid=-1, int gid=-1);
+  int _listxattr(const filepath &path, char *names, size_t len, bool followsym, int uid=-1, int gid=-1);
+  int _setxattr(const filepath &path, const char *name, const void *value, size_t len, int flags, bool followsym, int uid=-1, int gid=-1);
+  int _removexattr(const filepath &path, const char *nm, bool followsym, int uid=-1, int gid=-1);
   int _utimes(const filepath &path, utime_t mtime, utime_t atime, bool followsym, int uid=-1, int gid=-1);
   int _mknod(const filepath &path, mode_t mode, dev_t rdev, int uid=-1, int gid=-1);
   int _open(const filepath &path, int flags, mode_t mode, Fh **fhp, int uid=-1, int gid=-1);
@@ -901,6 +906,10 @@ public:
   Inode *_ll_get_inode(inodeno_t ino);
   int ll_getattr(inodeno_t ino, struct stat *st, int uid = -1, int gid = -1);
   int ll_setattr(inodeno_t ino, struct stat *st, int mask, int uid = -1, int gid = -1);
+  int ll_getxattr(inodeno_t ino, const char *name, void *value, size_t size, int uid=-1, int gid=-1);
+  int ll_setxattr(inodeno_t ino, const char *name, const void *value, size_t size, int flags, int uid=-1, int gid=-1);
+  int ll_removexattr(inodeno_t ino, const char *name, int uid=-1, int gid=-1);
+  int ll_listxattr(inodeno_t ino, char *list, size_t size, int uid=-1, int gid=-1);
   int ll_opendir(inodeno_t ino, void **dirpp, int uid = -1, int gid = -1);
   void ll_releasedir(void *dirp);
   int ll_readlink(inodeno_t ino, const char **value, int uid = -1, int gid = -1);
@@ -920,7 +929,6 @@ public:
   int ll_release(Fh *fh);
   int ll_statfs(inodeno_t, struct statvfs *stbuf);
 
-
   // failure
   void ms_handle_failure(Message*, const entity_inst_t& inst);
   void ms_handle_reset(const entity_addr_t& addr, entity_name_t last);
index f8987bc5cd1549652eaea04f92a0b8b41f8ce084..f835573e6bc5199f765f52582e8ed6a3117eb6d1 100644 (file)
@@ -78,6 +78,52 @@ static void ceph_ll_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
     fuse_reply_err(req, -r);
 }
 
+// XATTRS
+
+static void ceph_ll_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+                            const char *value, size_t size, int flags)
+{
+  const struct fuse_ctx *ctx = fuse_req_ctx(req);
+  int r = client->ll_setxattr(ino, name, value, size, flags, ctx->uid, ctx->gid);
+  fuse_reply_err(req, -r);
+}
+
+static void ceph_ll_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+{
+  const struct fuse_ctx *ctx = fuse_req_ctx(req);
+  char buf[size];
+  int r = client->ll_listxattr(ino, buf, size, ctx->uid, ctx->gid);
+  if (size == 0 && r >= 0)
+    fuse_reply_xattr(req, r);
+  else if (r >= 0)
+    fuse_reply_buf(req, buf, r);
+  else
+    fuse_reply_err(req, -r);
+}
+
+static void ceph_ll_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+                            size_t size)
+{
+  const struct fuse_ctx *ctx = fuse_req_ctx(req);
+  char buf[size];
+  int r = client->ll_getxattr(ino, name, buf, size, ctx->uid, ctx->gid);
+  if (size == 0 && r >= 0)
+    fuse_reply_xattr(req, r);
+  else if (r >= 0)
+    fuse_reply_buf(req, buf, r);
+  else
+    fuse_reply_err(req, -r);
+}
+
+static void ceph_ll_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
+{
+  const struct fuse_ctx *ctx = fuse_req_ctx(req);
+  int r = client->ll_removexattr(ino, name, ctx->uid, ctx->gid);
+  fuse_reply_err(req, -r);
+}
+
+
+
 static void ceph_ll_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
 {
   const struct fuse_ctx *ctx = fuse_req_ctx(req);
@@ -353,10 +399,10 @@ static struct fuse_lowlevel_ops ceph_ll_oper = {
  releasedir: ceph_ll_releasedir,
  fsyncdir: 0,
  statfs: ceph_ll_statfs,
- setxattr: 0,
- getxattr: 0,
- listxattr: 0,
- removexattr: 0,
+ setxattr: ceph_ll_setxattr,
+ getxattr: ceph_ll_getxattr,
+ listxattr: ceph_ll_listxattr,
+ removexattr: ceph_ll_removexattr,
  access: 0,
  create: ceph_ll_create,
  getlk: 0,
index 41ef0c0cc6dba0cea3748e9827956510e3385be4..3113d6c2fbd15bbe18a148ae05b7363631c85bcd 100644 (file)
@@ -471,11 +471,15 @@ enum {
        CEPH_MDS_OP_LUTIME    = 0x01101,
        CEPH_MDS_OP_LCHMOD    = 0x01102,
        CEPH_MDS_OP_LCHOWN    = 0x01103,
-
+       CEPH_MDS_OP_LSETXATTR = 0x01104,
+       CEPH_MDS_OP_LRMXATTR  = 0x01105,
+       
        CEPH_MDS_OP_STAT      = 0x10100,
        CEPH_MDS_OP_UTIME     = 0x11101,
        CEPH_MDS_OP_CHMOD     = 0x11102,
        CEPH_MDS_OP_CHOWN     = 0x11103,
+       CEPH_MDS_OP_SETXATTR  = 0x11104,
+       CEPH_MDS_OP_RMXATTR   = 0x11105,
 
        CEPH_MDS_OP_MKNOD     = 0x01201,
        CEPH_MDS_OP_LINK      = 0x01202,
@@ -492,6 +496,38 @@ enum {
        CEPH_MDS_OP_READDIR   = 0x00305,
 };
 
+static inline const char *ceph_mds_op_name(int op)
+{
+       switch (op) {
+       case CEPH_MDS_OP_FINDINODE: return "findinode";
+       case CEPH_MDS_OP_STAT:  return "stat";
+       case CEPH_MDS_OP_LSTAT:  return "lstat";
+       case CEPH_MDS_OP_UTIME: return "utime";
+       case CEPH_MDS_OP_LUTIME: return "lutime";
+       case CEPH_MDS_OP_CHMOD: return "chmod";
+       case CEPH_MDS_OP_LCHMOD: return "lchmod";
+       case CEPH_MDS_OP_CHOWN: return "chown";
+       case CEPH_MDS_OP_LCHOWN: return "lchown";
+       case CEPH_MDS_OP_SETXATTR: return "setxattr";
+       case CEPH_MDS_OP_LSETXATTR: return "lsetxattr";
+       case CEPH_MDS_OP_RMXATTR: return "rmxattr";
+       case CEPH_MDS_OP_LRMXATTR: return "lrmxattr";
+       case CEPH_MDS_OP_READDIR: return "readdir";
+       case CEPH_MDS_OP_MKNOD: return "mknod";
+       case CEPH_MDS_OP_LINK: return "link";
+       case CEPH_MDS_OP_UNLINK: return "unlink";
+       case CEPH_MDS_OP_RENAME: return "rename";
+       case CEPH_MDS_OP_MKDIR: return "mkdir";
+       case CEPH_MDS_OP_RMDIR: return "rmdir";
+       case CEPH_MDS_OP_SYMLINK: return "symlink";
+       case CEPH_MDS_OP_OPEN: return "open";
+       case CEPH_MDS_OP_TRUNCATE: return "truncate";
+       case CEPH_MDS_OP_LTRUNCATE: return "ltruncate";
+       case CEPH_MDS_OP_FSYNC: return "fsync";
+       default: return "unknown";
+       }
+}
+
 struct ceph_mds_request_head {
        struct ceph_entity_inst client_inst;
        ceph_tid_t tid, oldest_client_tid;
@@ -539,6 +575,9 @@ struct ceph_mds_request_head {
                struct {
                        __le64 length;
                } __attribute__ ((packed)) truncate;
+               struct {
+                       __le32 flags;
+               } __attribute__ ((packed)) setxattr;
        } __attribute__ ((packed)) args;
 } __attribute__ ((packed));
 
index a448f0fe80400e733b8593acc28638683373bb1d..ea484b8c42d1d3ccccdaf6bb75d0ca94e1231f66 100644 (file)
@@ -13,38 +13,6 @@ int ceph_debug_mdsc = -1;
 #include "messenger.h"
 #include "decode.h"
 
-/*
- * note: this also appears in messages/MClientRequest.h,
- * but i don't want it inline in the kernel.
- */
-const char *ceph_mds_op_name(int op)
-{
-  switch (op) {
-  case CEPH_MDS_OP_FINDINODE: return "findinode";
-  case CEPH_MDS_OP_STAT:  return "stat";
-  case CEPH_MDS_OP_LSTAT: return "lstat";
-  case CEPH_MDS_OP_UTIME: return "utime";
-  case CEPH_MDS_OP_LUTIME: return "lutime";
-  case CEPH_MDS_OP_CHMOD: return "chmod";
-  case CEPH_MDS_OP_LCHMOD: return "lchmod";
-  case CEPH_MDS_OP_CHOWN: return "chown";
-  case CEPH_MDS_OP_LCHOWN: return "lchown";
-  case CEPH_MDS_OP_READDIR: return "readdir";
-  case CEPH_MDS_OP_MKNOD: return "mknod";
-  case CEPH_MDS_OP_LINK: return "link";
-  case CEPH_MDS_OP_UNLINK: return "unlink";
-  case CEPH_MDS_OP_RENAME: return "rename";
-  case CEPH_MDS_OP_MKDIR: return "mkdir";
-  case CEPH_MDS_OP_RMDIR: return "rmdir";
-  case CEPH_MDS_OP_SYMLINK: return "symlink";
-  case CEPH_MDS_OP_OPEN: return "open";
-  case CEPH_MDS_OP_TRUNCATE: return "truncate";
-  case CEPH_MDS_OP_LTRUNCATE: return "ltruncate";
-  case CEPH_MDS_OP_FSYNC: return "fsync";
-  default: return "unknown";
-  }
-}
-
 static void send_msg_mds(struct ceph_mds_client *mdsc, struct ceph_msg *msg,
                         int mds)
 {
index f7ca356551324737a67039b86cd14a9a5c834d05..0ca4e53c03c2f1c8f2f880298f53e2d319ebd434 100644 (file)
 #include <fcntl.h>
 
 
-static inline const char* ceph_mds_op_name(int op) {
-  switch (op) {
-  case CEPH_MDS_OP_FINDINODE: return "findinode";
-  case CEPH_MDS_OP_STAT:  return "stat";
-  case CEPH_MDS_OP_LSTAT:  return "lstat";
-  case CEPH_MDS_OP_UTIME: return "utime";
-  case CEPH_MDS_OP_LUTIME: return "lutime";
-  case CEPH_MDS_OP_CHMOD: return "chmod";
-  case CEPH_MDS_OP_LCHMOD: return "lchmod";
-  case CEPH_MDS_OP_CHOWN: return "chown";
-  case CEPH_MDS_OP_LCHOWN: return "lchown";
-  case CEPH_MDS_OP_READDIR: return "readdir";
-  case CEPH_MDS_OP_MKNOD: return "mknod";
-  case CEPH_MDS_OP_LINK: return "link";
-  case CEPH_MDS_OP_UNLINK: return "unlink";
-  case CEPH_MDS_OP_RENAME: return "rename";
-  case CEPH_MDS_OP_MKDIR: return "mkdir";
-  case CEPH_MDS_OP_RMDIR: return "rmdir";
-  case CEPH_MDS_OP_SYMLINK: return "symlink";
-  case CEPH_MDS_OP_OPEN: return "open";
-  case CEPH_MDS_OP_TRUNCATE: return "truncate";
-  case CEPH_MDS_OP_LTRUNCATE: return "ltruncate";
-  case CEPH_MDS_OP_FSYNC: return "fsync";
-  default: return "unknown";
-  }
-}
-
 // metadata ops.
 
 static inline ostream& operator<<(ostream &out, const ceph_inopath_item &i) {