virtio-9p: Implement TXATTRCREATE
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Thu, 2 Sep 2010 05:39:07 +0000 (11:09 +0530)
committerAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Wed, 8 Sep 2010 17:26:41 +0000 (22:56 +0530)
TXATTRCREATE:  Prepare a fid for setting xattr value on a file system object.

 size[4] TXATTRCREATE tag[2] fid[4] name[s] attr_size[8] flags[4]
 size[4] RXATTRWALK tag[2]

txattrcreate gets a fid pointing to xattr. This fid can later be
used to get set the xattr value.

flag value is derived from set Linux setxattr. The manpage says
"The flags parameter can be used to refine the semantics of the operation.
XATTR_CREATE specifies a pure create, which fails if the named attribute
exists already. XATTR_REPLACE specifies a pure replace operation, which
fails if the named attribute does not already exist. By default (no flags),
the extended attribute will be created if need be, or will simply replace
the value if the attribute exists."

The actual setxattr operation happens when the fid is clunked. At that point
the written byte count and the attr_size specified in TXATTRCREATE should be
same otherwise an error will be returned.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
hw/file-op-9p.h
hw/virtio-9p-debug.c
hw/virtio-9p-local.c
hw/virtio-9p.c
hw/virtio-9p.h

index 3a21cbec529030c35ef0640059af41a8b04d6456..e54f3585ea73299b2123b02aef01cc38c2904dfa 100644 (file)
@@ -78,6 +78,8 @@ typedef struct FileOperations
     ssize_t (*lgetxattr)(FsContext *, const char *,
                          const char *, void *, size_t);
     ssize_t (*llistxattr)(FsContext *, const char *, void *, size_t);
+    int (*lsetxattr)(FsContext *, const char *,
+                     const char *, void *, size_t, int);
     void *opaque;
 } FileOperations;
 #endif
index 4554eb6f6df436a49d599af2adfde72d98110995..ad680545c6b92c709f5a1efe314f29515107c606 100644 (file)
@@ -588,6 +588,15 @@ void pprint_pdu(V9fsPDU *pdu)
     case P9_RXATTRWALK:
         fprintf(llogfile, "RXATTRWALK: (");
         pprint_int64(pdu, 1, &offset, "xattrsize");
+    case P9_TXATTRCREATE:
+        fprintf(llogfile, "TXATTRCREATE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_int64(pdu, 0, &offset, ", xattrsize");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        break;
+    case P9_RXATTRCREATE:
+        fprintf(llogfile, "RXATTRCREATE: (");
         break;
     default:
         fprintf(llogfile, "unknown(%d): (", pdu->id);
index a6b5e6603a4b39f03c54eed5b951913bf635b80a..6c39256475f0946b0006c3c97b703c385c2d35e8 100644 (file)
@@ -486,6 +486,12 @@ static ssize_t local_llistxattr(FsContext *ctx, const char *path,
     return llistxattr(rpath(ctx, path), value, size);
 }
 
+static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
+                           void *value, size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), name, value, size, flags);
+}
+
 FileOperations local_ops = {
     .lstat = local_lstat,
     .readlink = local_readlink,
@@ -516,4 +522,5 @@ FileOperations local_ops = {
     .statfs = local_statfs,
     .lgetxattr = local_lgetxattr,
     .llistxattr = local_llistxattr,
+    .lsetxattr = local_lsetxattr,
 };
index 656c721f95e72be319102a816c155cb117678651..a2ca422abcc2e083e3afee28897800cc247212b2 100644 (file)
@@ -278,6 +278,14 @@ static ssize_t v9fs_do_llistxattr(V9fsState *s, V9fsString *path,
                               value, size);
 }
 
+static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
+                             V9fsString *xattr_name,
+                             void *value, size_t size, int flags)
+{
+    return s->ops->lsetxattr(&s->ctx, path->data,
+                             xattr_name->data, value, size, flags);
+}
+
 static void v9fs_string_init(V9fsString *str)
 {
     str->data = NULL;
@@ -431,8 +439,39 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
     return f;
 }
 
+static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
+{
+    int retval = 0;
+
+    if (fidp->fs.xattr.copied_len == -1) {
+        /* getxattr/listxattr fid */
+        goto free_value;
+    }
+    /*
+     * if this is fid for setxattr. clunk should
+     * result in setxattr localcall
+     */
+    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
+        /* clunk after partial write */
+        retval = -EINVAL;
+        goto free_out;
+    }
+    retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
+                               fidp->fs.xattr.value,
+                               fidp->fs.xattr.len,
+                               fidp->fs.xattr.flags);
+free_out:
+    v9fs_string_free(&fidp->fs.xattr.name);
+free_value:
+    if (fidp->fs.xattr.value) {
+        qemu_free(fidp->fs.xattr.value);
+    }
+    return retval;
+}
+
 static int free_fid(V9fsState *s, int32_t fid)
 {
+    int retval = 0;
     V9fsFidState **fidpp, *fidp;
 
     for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
@@ -453,14 +492,12 @@ static int free_fid(V9fsState *s, int32_t fid)
     } else if (fidp->fid_type == P9_FID_DIR) {
         v9fs_do_closedir(s, fidp->fs.dir);
     } else if (fidp->fid_type == P9_FID_XATTR) {
-        if (fidp->fs.xattr.value) {
-            qemu_free(fidp->fs.xattr.value);
-        }
+        retval = v9fs_xattr_fid_clunk(s, fidp);
     }
     v9fs_string_free(&fidp->path);
     qemu_free(fidp);
 
-    return 0;
+    return retval;
 }
 
 #define P9_QID_TYPE_DIR         0x80
@@ -2211,6 +2248,48 @@ out:
     qemu_free(vs);
 }
 
+static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
+{
+    int i, to_copy;
+    ssize_t err = 0;
+    int write_count;
+    int64_t xattr_len;
+
+    xattr_len = vs->fidp->fs.xattr.len;
+    write_count = xattr_len - vs->off;
+    if (write_count > vs->count) {
+        write_count = vs->count;
+    } else if (write_count < 0) {
+        /*
+         * write beyond XATTR value len specified in
+         * xattrcreate
+         */
+        err = -ENOSPC;
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
+    err = vs->offset;
+    vs->fidp->fs.xattr.copied_len += write_count;
+    /*
+     * Now copy the content from sg list
+     */
+    for (i = 0; i < vs->cnt; i++) {
+        if (write_count > vs->sg[i].iov_len) {
+            to_copy = vs->sg[i].iov_len;
+        } else {
+            to_copy = write_count;
+        }
+        memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
+               vs->sg[i].iov_base, to_copy);
+        /* updating vs->off since we are not using below */
+        vs->off += to_copy;
+        write_count -= to_copy;
+    }
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
 static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
 {
     int32_t fid;
@@ -2226,7 +2305,7 @@ static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
     vs->len = 0;
 
     pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
-                    vs->sg, &vs->cnt);
+                  vs->sg, &vs->cnt);
 
     vs->fidp = lookup_fid(s, fid);
     if (vs->fidp == NULL) {
@@ -2234,11 +2313,21 @@ static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
         goto out;
     }
 
-    if (vs->fidp->fs.fd == -1) {
+    if (vs->fidp->fid_type == P9_FID_FILE) {
+        if (vs->fidp->fs.fd == -1) {
+            err = -EINVAL;
+            goto out;
+        }
+    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
+        /*
+         * setxattr operation
+         */
+        v9fs_xattr_write(s, vs);
+        return;
+    } else {
         err = -EINVAL;
         goto out;
     }
-
     err = v9fs_do_lseek(s, vs->fidp->fs.fd, vs->off, SEEK_SET);
 
     v9fs_write_post_lseek(s, vs, err);
@@ -3276,6 +3365,41 @@ out:
     qemu_free(vs);
 }
 
+static void v9fs_xattrcreate(V9fsState *s, V9fsPDU *pdu)
+{
+    int flags;
+    int32_t fid;
+    ssize_t err = 0;
+    V9fsXattrState *vs;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dsqd",
+                  &fid, &vs->name, &vs->size, &flags);
+
+    vs->file_fidp = lookup_fid(s, fid);
+    if (vs->file_fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    /* Make the file fid point to xattr */
+    vs->xattr_fidp = vs->file_fidp;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = 0;
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fs.xattr.flags = flags;
+    v9fs_string_init(&vs->xattr_fidp->fs.xattr.name);
+    v9fs_string_copy(&vs->xattr_fidp->fs.xattr.name, &vs->name);
+    vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
 
 typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
 
@@ -3285,6 +3409,7 @@ static pdu_handler_t *pdu_handlers[] = {
     [P9_TGETATTR] = v9fs_getattr,
     [P9_TSETATTR] = v9fs_setattr,
     [P9_TXATTRWALK] = v9fs_xattrwalk,
+    [P9_TXATTRCREATE] = v9fs_xattrcreate,
     [P9_TMKNOD] = v9fs_mknod,
     [P9_TRENAME] = v9fs_rename,
     [P9_TMKDIR] = v9fs_mkdir,
index 005df492904d7a69921a2ccd00bcb9f220cb2ecc..016ba1dcf7b9aef8489a9e8558a724ce6d35200b 100644 (file)
@@ -31,6 +31,8 @@ enum {
     P9_RSETATTR,
     P9_TXATTRWALK = 30,
     P9_RXATTRWALK,
+    P9_TXATTRCREATE = 32,
+    P9_RXATTRCREATE,
     P9_TREADDIR = 40,
     P9_RREADDIR,
     P9_TLINK = 70,