From 16a9e8c8735499bd7c0ab6e3b99b01f86df91a9b Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 18 May 2008 09:51:42 -0700 Subject: [PATCH] client: xattr ops, fuse hooks --- src/client/Client.cc | 153 ++++++++++++++++++++++++++++++++++ src/client/Client.h | 10 ++- src/client/fuse_ll.cc | 54 +++++++++++- src/include/ceph_fs.h | 41 ++++++++- src/kernel/mds_client.c | 32 ------- src/messages/MClientRequest.h | 27 ------ 6 files changed, 252 insertions(+), 65 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 368887edf6b21..dc5449a9d7331 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -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::iterator p = in->xattrs.begin(); + p != in->xattrs.end(); + p++) + r += p->second.length() + 1; + + if (size != 0) { + if (size >= (unsigned)r) { + for (map::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); diff --git a/src/client/Client.h b/src/client/Client.h index d93df8258edb5..5e640a2bd05b4 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -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 xattrs; map fragmap; // known frag -> mds mappings list 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); diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index f8987bc5cd154..f835573e6bc51 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -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, diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index 41ef0c0cc6dba..3113d6c2fbd15 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -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)); diff --git a/src/kernel/mds_client.c b/src/kernel/mds_client.c index a448f0fe80400..ea484b8c42d1d 100644 --- a/src/kernel/mds_client.c +++ b/src/kernel/mds_client.c @@ -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) { diff --git a/src/messages/MClientRequest.h b/src/messages/MClientRequest.h index f7ca356551324..0ca4e53c03c2f 100644 --- a/src/messages/MClientRequest.h +++ b/src/messages/MClientRequest.h @@ -44,33 +44,6 @@ #include -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) { -- 2.39.5