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?
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);
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;
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);
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);
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);
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);
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,
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,
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;
struct {
__le64 length;
} __attribute__ ((packed)) truncate;
+ struct {
+ __le32 flags;
+ } __attribute__ ((packed)) setxattr;
} __attribute__ ((packed)) args;
} __attribute__ ((packed));
#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)
{
#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) {