[PATCH 8/13] Filesystem in Userspace

From: Miklos Szeredi
Date: Sat Nov 20 2004 - 18:47:45 EST


This patch adds the extended attribute operations to FUSE.

The following operations are added:

o getxattr
o setxattr
o listxattr
o removexattr

Signed-off-by: Miklos Szeredi <miklos@xxxxxxxxxx>
--- linux-2.6.10-rc2/fs/fuse/dir.c 2004-11-20 22:56:23.000000000 +0100
+++ linux-2.6.10-rc2-fuse/fs/fuse/dir.c 2004-11-20 22:56:21.000000000 +0100
@@ -877,6 +877,177 @@ static struct dentry *fuse_lookup(struct
return d_splice_alias(inode, entry);
}

+static int fuse_setxattr(struct dentry *entry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct inode *inode = entry->d_inode;
+ struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_req *req;
+ struct fuse_setxattr_in inarg;
+ int err;
+
+ if (size > FUSE_XATTR_SIZE_MAX)
+ return -E2BIG;
+
+ if (fc->no_setxattr)
+ return -EOPNOTSUPP;
+
+ req = fuse_get_request(fc);
+ if (!req)
+ return -ERESTARTSYS;
+
+ memset(&inarg, 0, sizeof(inarg));
+ inarg.size = size;
+ inarg.flags = flags;
+ req->in.h.opcode = FUSE_SETXATTR;
+ req->in.h.nodeid = fi->nodeid;
+ req->in.numargs = 3;
+ req->in.args[0].size = sizeof(inarg);
+ req->in.args[0].value = &inarg;
+ req->in.args[1].size = strlen(name) + 1;
+ req->in.args[1].value = name;
+ req->in.args[2].size = size;
+ req->in.args[2].value = value;
+ request_send(fc, req);
+ err = req->out.h.error;
+ if (err == -ENOSYS) {
+ fc->no_setxattr = 1;
+ err = -EOPNOTSUPP;
+ }
+ fuse_put_request(fc, req);
+ return err;
+}
+
+static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
+ void *value, size_t size)
+{
+ struct inode *inode = entry->d_inode;
+ struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_req *req;
+ struct fuse_getxattr_in inarg;
+ struct fuse_getxattr_out outarg;
+ ssize_t ret;
+
+ if (fc->no_getxattr)
+ return -EOPNOTSUPP;
+
+ req = fuse_get_request(fc);
+ if (!req)
+ return -ERESTARTSYS;
+
+ memset(&inarg, 0, sizeof(inarg));
+ inarg.size = size;
+ req->in.h.opcode = FUSE_GETXATTR;
+ req->in.h.nodeid = fi->nodeid;
+ req->in.numargs = 2;
+ req->in.args[0].size = sizeof(inarg);
+ req->in.args[0].value = &inarg;
+ req->in.args[1].size = strlen(name) + 1;
+ req->in.args[1].value = name;
+ /* This is really two different operations rolled into one */
+ req->out.numargs = 1;
+ if (size) {
+ req->out.argvar = 1;
+ req->out.args[0].size = size;
+ req->out.args[0].value = value;
+ } else {
+ req->out.args[0].size = sizeof(outarg);
+ req->out.args[0].value = &outarg;
+ }
+ request_send(fc, req);
+ ret = req->out.h.error;
+ if (!ret)
+ ret = size ? req->out.args[0].size : outarg.size;
+ else {
+ if (ret == -ENOSYS) {
+ fc->no_getxattr = 1;
+ ret = -EOPNOTSUPP;
+ }
+ }
+ fuse_put_request(fc, req);
+ return ret;
+}
+
+static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
+{
+ struct inode *inode = entry->d_inode;
+ struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_req *req;
+ struct fuse_getxattr_in inarg;
+ struct fuse_getxattr_out outarg;
+ ssize_t ret;
+
+ if (fc->no_listxattr)
+ return -EOPNOTSUPP;
+
+ req = fuse_get_request(fc);
+ if (!req)
+ return -ERESTARTSYS;
+
+ memset(&inarg, 0, sizeof(inarg));
+ inarg.size = size;
+ req->in.h.opcode = FUSE_LISTXATTR;
+ req->in.h.nodeid = fi->nodeid;
+ req->in.numargs = 1;
+ req->in.args[0].size = sizeof(inarg);
+ req->in.args[0].value = &inarg;
+ /* This is really two different operations rolled into one */
+ req->out.numargs = 1;
+ if (size) {
+ req->out.argvar = 1;
+ req->out.args[0].size = size;
+ req->out.args[0].value = list;
+ } else {
+ req->out.args[0].size = sizeof(outarg);
+ req->out.args[0].value = &outarg;
+ }
+ request_send(fc, req);
+ ret = req->out.h.error;
+ if (!ret)
+ ret = size ? req->out.args[0].size : outarg.size;
+ else {
+ if (ret == -ENOSYS) {
+ fc->no_listxattr = 1;
+ ret = -EOPNOTSUPP;
+ }
+ }
+ fuse_put_request(fc, req);
+ return ret;
+}
+
+static int fuse_removexattr(struct dentry *entry, const char *name)
+{
+ struct inode *inode = entry->d_inode;
+ struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_req *req;
+ int err;
+
+ if (fc->no_removexattr)
+ return -EOPNOTSUPP;
+
+ req = fuse_get_request(fc);
+ if (!req)
+ return -ERESTARTSYS;
+
+ req->in.h.opcode = FUSE_REMOVEXATTR;
+ req->in.h.nodeid = fi->nodeid;
+ req->in.numargs = 1;
+ req->in.args[0].size = strlen(name) + 1;
+ req->in.args[0].value = name;
+ request_send(fc, req);
+ err = req->out.h.error;
+ if (err == -ENOSYS) {
+ fc->no_removexattr = 1;
+ err = -EOPNOTSUPP;
+ }
+ fuse_put_request(fc, req);
+ return err;
+}
+
static struct inode_operations fuse_dir_inode_operations = {
.lookup = fuse_lookup,
.mkdir = fuse_mkdir,
@@ -890,6 +1061,10 @@ static struct inode_operations fuse_dir_
.mknod = fuse_mknod,
.permission = fuse_permission,
.getattr = fuse_getattr,
+ .setxattr = fuse_setxattr,
+ .getxattr = fuse_getxattr,
+ .listxattr = fuse_listxattr,
+ .removexattr = fuse_removexattr,
};

static struct file_operations fuse_dir_operations = {
@@ -903,6 +1078,10 @@ static struct inode_operations fuse_file
.setattr = fuse_setattr,
.permission = fuse_permission,
.getattr = fuse_getattr,
+ .setxattr = fuse_setxattr,
+ .getxattr = fuse_getxattr,
+ .listxattr = fuse_listxattr,
+ .removexattr = fuse_removexattr,
};

static struct inode_operations fuse_symlink_inode_operations = {
@@ -910,6 +1089,10 @@ static struct inode_operations fuse_syml
.readlink = fuse_readlink,
.follow_link = fuse_follow_link,
.getattr = fuse_getattr,
+ .setxattr = fuse_setxattr,
+ .getxattr = fuse_getxattr,
+ .listxattr = fuse_listxattr,
+ .removexattr = fuse_removexattr,
};

static struct dentry_operations fuse_dentry_operations = {
--- linux-2.6.10-rc2/fs/fuse/fuse_i.h 2004-11-20 22:56:23.000000000 +0100
+++ linux-2.6.10-rc2-fuse/fs/fuse/fuse_i.h 2004-11-20 22:56:23.000000000 +0100
@@ -152,6 +152,18 @@ struct fuse_conn {

/** Is flush not implemented by fs? */
unsigned int no_flush : 1;
+
+ /** Is setxattr not implemented by fs? */
+ unsigned int no_setxattr : 1;
+
+ /** Is getxattr not implemented by fs? */
+ unsigned int no_getxattr : 1;
+
+ /** Is listxattr not implemented by fs? */
+ unsigned int no_listxattr : 1;
+
+ /** Is removexattr not implemented by fs? */
+ unsigned int no_removexattr : 1;
};

struct fuse_getdir_out_i {
--- linux-2.6.10-rc2/include/linux/fuse.h 2004-11-20 22:56:23.000000000 +0100
+++ linux-2.6.10-rc2-fuse/include/linux/fuse.h 2004-11-20 22:56:22.000000000 +0100
@@ -79,10 +79,10 @@ enum fuse_opcode {
FUSE_RELEASE = 18,
/* FUSE_INVALIDATE = 19, */
FUSE_FSYNC = 20,
- /* FUSE_SETXATTR = 21, */
- /* FUSE_GETXATTR = 22, */
- /* FUSE_LISTXATTR = 23, */
- /* FUSE_REMOVEXATTR = 24, */
+ FUSE_SETXATTR = 21,
+ FUSE_GETXATTR = 22,
+ FUSE_LISTXATTR = 23,
+ FUSE_REMOVEXATTR = 24,
FUSE_FLUSH = 25,
};

@@ -91,6 +91,7 @@ enum fuse_opcode {

#define FUSE_NAME_MAX 1024
#define FUSE_SYMLINK_MAX 4096
+#define FUSE_XATTR_SIZE_MAX 4096

struct fuse_entry_out {
unsigned long nodeid; /* Inode ID */
@@ -184,6 +185,19 @@ struct fuse_fsync_in {
int datasync;
};

+struct fuse_setxattr_in {
+ unsigned int size;
+ unsigned int flags;
+};
+
+struct fuse_getxattr_in {
+ unsigned int size;
+};
+
+struct fuse_getxattr_out {
+ unsigned int size;
+};
+
struct fuse_in_header {
int unique;
enum fuse_opcode opcode;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/