diff mbox series

[v3,7/7] Mini-OS: add read and write support to 9pfsfront

Message ID 20230213084412.21065-8-jgross@suse.com (mailing list archive)
State New, archived
Headers show
Series Mini-OS: add minimal 9pfs support | expand

Commit Message

Jürgen Groß Feb. 13, 2023, 8:44 a.m. UTC
Add support to read from and write to a file handled by 9pfsfront.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- add check for max message size
- return EAGAIN in case no free request got (Samuel Thibault)
- loop until all data read/written (Samuel Thibault)
V3:
- use an exact limit for read/write (Samuel Thibault)
- log read(write errors (Samuel Thibault)
---
 9pfront.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 216 insertions(+)

Comments

Samuel Thibault Feb. 13, 2023, 11:13 p.m. UTC | #1
Juergen Gross, le lun. 13 févr. 2023 09:44:12 +0100, a ecrit:
> Add support to read from and write to a file handled by 9pfsfront.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>

Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

> ---
> V2:
> - add check for max message size
> - return EAGAIN in case no free request got (Samuel Thibault)
> - loop until all data read/written (Samuel Thibault)
> V3:
> - use an exact limit for read/write (Samuel Thibault)
> - log read(write errors (Samuel Thibault)
> ---
>  9pfront.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 216 insertions(+)
> 
> diff --git a/9pfront.c b/9pfront.c
> index fb2e5669..5da8a365 100644
> --- a/9pfront.c
> +++ b/9pfront.c
> @@ -72,7 +72,10 @@ struct file_9pfs {
>  #define P9_CMD_WALK       110
>  #define P9_CMD_OPEN       112
>  #define P9_CMD_CREATE     114
> +#define P9_CMD_READ       116
> +#define P9_CMD_WRITE      118
>  #define P9_CMD_CLUNK      120
> +#define P9_CMD_STAT       124
>  
>  /* P9 protocol open flags. */
>  #define P9_OREAD            0   /* read */
> @@ -88,11 +91,39 @@ struct p9_header {
>      uint16_t tag;
>  } __attribute__((packed));
>  
> +struct p9_stat {
> +    uint16_t size;
> +    uint16_t type;
> +    uint32_t dev;
> +    uint8_t qid[P9_QID_SIZE];
> +    uint32_t mode;
> +    uint32_t atime;
> +    uint32_t mtime;
> +    uint64_t length;
> +    char *name;
> +    char *uid;
> +    char *gid;
> +    char *muid;
> +    char *extension;
> +    uint32_t n_uid;
> +    uint32_t n_gid;
> +    uint32_t n_muid;
> +};
> +
>  #define P9_VERSION        "9P2000.u"
>  #define P9_ROOT_FID       0
>  
>  static unsigned int ftype_9pfs;
>  
> +static void free_stat(struct p9_stat *stat)
> +{
> +    free(stat->name);
> +    free(stat->uid);
> +    free(stat->gid);
> +    free(stat->muid);
> +    free(stat->extension);
> +}
> +
>  static unsigned int get_fid(struct dev_9pfs *dev)
>  {
>      unsigned int fid;
> @@ -181,9 +212,12 @@ static void copy_from_ring(struct dev_9pfs *dev, void *data, unsigned int len)
>   *    Only valid for sending.
>   * u: 2 byte unsigned integer (uint16_t)
>   * U: 4 byte unsigned integer (uint32_t)
> + * L: 8 byte unsigned integer (uint64_t)
>   * S: String (2 byte length + <length> characters)
>   *    in the rcv_9p() case the data for string is allocated (length omitted,
>   *    string terminated by a NUL character)
> + * D: Binary data (4 byte length + <length> bytes of data), requires a length
> + *    and a buffer pointer parameter.
>   * Q: A 13 byte "qid", consisting of 1 byte file type, 4 byte file version
>   *    and 8 bytes unique file id. Only valid for receiving.
>   */
> @@ -192,10 +226,12 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...)
>      struct p9_header hdr;
>      va_list ap, aq;
>      const char *f;
> +    uint64_t longval;
>      uint32_t intval;
>      uint16_t shortval;
>      uint16_t len;
>      uint8_t byte;
> +    uint8_t *data;
>      char *strval;
>  
>      hdr.size = sizeof(hdr);
> @@ -221,11 +257,21 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...)
>              hdr.size += 4;
>              intval = va_arg(aq, unsigned int);
>              break;
> +        case 'L':
> +            hdr.size += 8;
> +            longval = va_arg(aq, uint64_t);
> +            break;
>          case 'S':
>              hdr.size += 2;
>              strval = va_arg(aq, char *);
>              hdr.size += strlen(strval);
>              break;
> +        case 'D':
> +            hdr.size += 4;
> +            intval = va_arg(aq, unsigned int);
> +            hdr.size += intval;
> +            data = va_arg(aq, uint8_t *);
> +            break;
>          default:
>              printk("send_9p: unknown format character %c\n", *f);
>              break;
> @@ -258,12 +304,22 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...)
>              intval = va_arg(ap, unsigned int);
>              copy_to_ring(dev, &intval, sizeof(intval));
>              break;
> +        case 'L':
> +            longval = va_arg(ap, uint64_t);
> +            copy_to_ring(dev, &longval, sizeof(longval));
> +            break;
>          case 'S':
>              strval = va_arg(ap, char *);
>              len = strlen(strval);
>              copy_to_ring(dev, &len, sizeof(len));
>              copy_to_ring(dev, strval, len);
>              break;
> +        case 'D':
> +            intval = va_arg(ap, unsigned int);
> +            copy_to_ring(dev, &intval, sizeof(intval));
> +            data = va_arg(ap, uint8_t *);
> +            copy_to_ring(dev, data, intval);
> +            break;
>          }
>      }
>  
> @@ -348,6 +404,8 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req,
>      uint32_t err;
>      uint16_t *shortval;
>      uint32_t *val;
> +    uint64_t *longval;
> +    uint8_t *data;
>      char **strval;
>      uint8_t *qval;
>  
> @@ -412,6 +470,10 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req,
>              val = va_arg(ap, uint32_t *);
>              copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val));
>              break;
> +        case 'L':
> +            longval = va_arg(ap, uint64_t *);
> +            copy_bufs(&buf1, &buf2, &len1, &len2, longval, sizeof(*longval));
> +            break;
>          case 'S':
>              strval = va_arg(ap, char **);
>              copy_bufs(&buf1, &buf2, &len1, &len2, &len, sizeof(len));
> @@ -419,6 +481,12 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req,
>              copy_bufs(&buf1, &buf2, &len1, &len2, *strval, len);
>              (*strval)[len] = 0;
>              break;
> +        case 'D':
> +            val = va_arg(ap, uint32_t *);
> +            data = va_arg(ap, uint8_t *);
> +            copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val));
> +            copy_bufs(&buf1, &buf2, &len1, &len2, data, *val);
> +            break;
>          case 'Q':
>              qval = va_arg(ap, uint8_t *);
>              copy_bufs(&buf1, &buf2, &len1, &len2, qval, P9_QID_SIZE);
> @@ -640,6 +708,115 @@ static int p9_create(struct dev_9pfs *dev, uint32_t fid, char *path,
>      return ret;
>  }
>  
> +static int p9_stat(struct dev_9pfs *dev, uint32_t fid, struct p9_stat *stat)
> +{
> +    struct req *req = get_free_req(dev);
> +    int ret;
> +
> +    if ( !req )
> +        return EAGAIN;
> +
> +    memset(stat, 0, sizeof(*stat));
> +    req->cmd = P9_CMD_STAT;
> +    send_9p(dev, req, "U", fid);
> +    rcv_9p(dev, req, "uuUQUUULSSSSSUUU", &stat->size, &stat->type, &stat->dev,
> +           stat->qid, &stat->mode, &stat->atime, &stat->mtime, &stat->length,
> +           &stat->name, &stat->uid, &stat->gid, &stat->muid, &stat->extension,
> +           &stat->n_uid, &stat->n_gid, &stat->n_muid);
> +
> +    ret = req->result;
> +
> +    put_free_req(dev, req);
> +
> +    return ret;
> +}
> +
> +static int p9_read(struct dev_9pfs *dev, uint32_t fid, uint64_t offset,
> +                   uint8_t *data, uint32_t len)
> +{
> +    struct req *req = get_free_req(dev);
> +    int ret = 0;
> +    uint32_t count, count_max;
> +
> +    if ( !req )
> +    {
> +        errno = EAGAIN;
> +        return -1;
> +    }
> +    req->cmd = P9_CMD_READ;
> +    count_max = dev->msize_max - (sizeof(struct p9_header) + sizeof(uint32_t));
> +
> +    while ( len )
> +    {
> +        count = len;
> +        if ( count > count_max )
> +            count = count_max;
> +
> +        send_9p(dev, req, "ULU", fid, offset, count);
> +        rcv_9p(dev, req, "D", &count, data);
> +
> +        if ( !count )
> +            break;
> +        if ( req->result )
> +        {
> +            ret = -1;
> +            errno = EIO;
> +            printk("9pfs: read got error %d\n", req->result);
> +            break;
> +        }
> +        ret += count;
> +        offset += count;
> +        data += count;
> +        len -= count;
> +    }
> +
> +    put_free_req(dev, req);
> +
> +    return ret;
> +}
> +
> +static int p9_write(struct dev_9pfs *dev, uint32_t fid, uint64_t offset,
> +                    const uint8_t *data, uint32_t len)
> +{
> +    struct req *req = get_free_req(dev);
> +    int ret = 0;
> +    uint32_t count, count_max;
> +
> +    if ( !req )
> +    {
> +        errno = EAGAIN;
> +        return -1;
> +    }
> +    req->cmd = P9_CMD_WRITE;
> +    count_max = dev->msize_max - (sizeof(struct p9_header) + sizeof(uint32_t) +
> +                                  sizeof(uint64_t) + sizeof(uint32_t));
> +
> +    while ( len )
> +    {
> +        count = len;
> +        if ( count > count_max )
> +            count = count_max;
> +
> +        send_9p(dev, req, "ULD", fid, offset, count, data);
> +        rcv_9p(dev, req, "U", &count);
> +        if ( req->result )
> +        {
> +            ret = -1;
> +            errno = EIO;
> +            printk("9pfs: write got error %d\n", req->result);
> +            break;
> +        }
> +        ret += count;
> +        offset += count;
> +        data += count;
> +        len -= count;
> +    }
> +
> +    put_free_req(dev, req);
> +
> +    return ret;
> +}
> +
>  /*
>   * Walk from root <steps> levels with the levels listed in <*paths> as a
>   * sequence of names. Returns the number of steps not having been able to
> @@ -731,6 +908,43 @@ static void intr_9pfs(evtchn_port_t port, struct pt_regs *regs, void *data)
>      wake_up(&dev->waitq);
>  }
>  
> +static int read_9pfs(struct file *file, void *buf, size_t nbytes)
> +{
> +    struct file_9pfs *f9pfs = file->filedata;
> +    int ret;
> +
> +    ret = p9_read(f9pfs->dev, f9pfs->fid, file->offset, buf, nbytes);
> +    if ( ret >= 0 )
> +        file->offset += ret;
> +
> +    return ret;
> +}
> +
> +static int write_9pfs(struct file *file, const void *buf, size_t nbytes)
> +{
> +    struct file_9pfs *f9pfs = file->filedata;
> +    struct p9_stat stat;
> +    int ret;
> +
> +    if ( f9pfs->append )
> +    {
> +        ret = p9_stat(f9pfs->dev, f9pfs->fid, &stat);
> +        free_stat(&stat);
> +        if ( ret )
> +        {
> +            errno = EIO;
> +            return -1;
> +        }
> +        file->offset = stat.length;
> +    }
> +
> +    ret = p9_write(f9pfs->dev, f9pfs->fid, file->offset, buf, nbytes);
> +    if ( ret >= 0 )
> +        file->offset += ret;
> +
> +    return ret;
> +}
> +
>  static int close_9pfs(struct file *file)
>  {
>      struct file_9pfs *f9pfs = file->filedata;
> @@ -1072,6 +1286,8 @@ void shutdown_9pfront(void *dev)
>  
>  static const struct file_ops ops_9pfs = {
>      .name = "9pfs",
> +    .read = read_9pfs,
> +    .write = write_9pfs,
>      .close = close_9pfs,
>  };
>  
> -- 
> 2.35.3
>
diff mbox series

Patch

diff --git a/9pfront.c b/9pfront.c
index fb2e5669..5da8a365 100644
--- a/9pfront.c
+++ b/9pfront.c
@@ -72,7 +72,10 @@  struct file_9pfs {
 #define P9_CMD_WALK       110
 #define P9_CMD_OPEN       112
 #define P9_CMD_CREATE     114
+#define P9_CMD_READ       116
+#define P9_CMD_WRITE      118
 #define P9_CMD_CLUNK      120
+#define P9_CMD_STAT       124
 
 /* P9 protocol open flags. */
 #define P9_OREAD            0   /* read */
@@ -88,11 +91,39 @@  struct p9_header {
     uint16_t tag;
 } __attribute__((packed));
 
+struct p9_stat {
+    uint16_t size;
+    uint16_t type;
+    uint32_t dev;
+    uint8_t qid[P9_QID_SIZE];
+    uint32_t mode;
+    uint32_t atime;
+    uint32_t mtime;
+    uint64_t length;
+    char *name;
+    char *uid;
+    char *gid;
+    char *muid;
+    char *extension;
+    uint32_t n_uid;
+    uint32_t n_gid;
+    uint32_t n_muid;
+};
+
 #define P9_VERSION        "9P2000.u"
 #define P9_ROOT_FID       0
 
 static unsigned int ftype_9pfs;
 
+static void free_stat(struct p9_stat *stat)
+{
+    free(stat->name);
+    free(stat->uid);
+    free(stat->gid);
+    free(stat->muid);
+    free(stat->extension);
+}
+
 static unsigned int get_fid(struct dev_9pfs *dev)
 {
     unsigned int fid;
@@ -181,9 +212,12 @@  static void copy_from_ring(struct dev_9pfs *dev, void *data, unsigned int len)
  *    Only valid for sending.
  * u: 2 byte unsigned integer (uint16_t)
  * U: 4 byte unsigned integer (uint32_t)
+ * L: 8 byte unsigned integer (uint64_t)
  * S: String (2 byte length + <length> characters)
  *    in the rcv_9p() case the data for string is allocated (length omitted,
  *    string terminated by a NUL character)
+ * D: Binary data (4 byte length + <length> bytes of data), requires a length
+ *    and a buffer pointer parameter.
  * Q: A 13 byte "qid", consisting of 1 byte file type, 4 byte file version
  *    and 8 bytes unique file id. Only valid for receiving.
  */
@@ -192,10 +226,12 @@  static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...)
     struct p9_header hdr;
     va_list ap, aq;
     const char *f;
+    uint64_t longval;
     uint32_t intval;
     uint16_t shortval;
     uint16_t len;
     uint8_t byte;
+    uint8_t *data;
     char *strval;
 
     hdr.size = sizeof(hdr);
@@ -221,11 +257,21 @@  static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...)
             hdr.size += 4;
             intval = va_arg(aq, unsigned int);
             break;
+        case 'L':
+            hdr.size += 8;
+            longval = va_arg(aq, uint64_t);
+            break;
         case 'S':
             hdr.size += 2;
             strval = va_arg(aq, char *);
             hdr.size += strlen(strval);
             break;
+        case 'D':
+            hdr.size += 4;
+            intval = va_arg(aq, unsigned int);
+            hdr.size += intval;
+            data = va_arg(aq, uint8_t *);
+            break;
         default:
             printk("send_9p: unknown format character %c\n", *f);
             break;
@@ -258,12 +304,22 @@  static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...)
             intval = va_arg(ap, unsigned int);
             copy_to_ring(dev, &intval, sizeof(intval));
             break;
+        case 'L':
+            longval = va_arg(ap, uint64_t);
+            copy_to_ring(dev, &longval, sizeof(longval));
+            break;
         case 'S':
             strval = va_arg(ap, char *);
             len = strlen(strval);
             copy_to_ring(dev, &len, sizeof(len));
             copy_to_ring(dev, strval, len);
             break;
+        case 'D':
+            intval = va_arg(ap, unsigned int);
+            copy_to_ring(dev, &intval, sizeof(intval));
+            data = va_arg(ap, uint8_t *);
+            copy_to_ring(dev, data, intval);
+            break;
         }
     }
 
@@ -348,6 +404,8 @@  static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req,
     uint32_t err;
     uint16_t *shortval;
     uint32_t *val;
+    uint64_t *longval;
+    uint8_t *data;
     char **strval;
     uint8_t *qval;
 
@@ -412,6 +470,10 @@  static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req,
             val = va_arg(ap, uint32_t *);
             copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val));
             break;
+        case 'L':
+            longval = va_arg(ap, uint64_t *);
+            copy_bufs(&buf1, &buf2, &len1, &len2, longval, sizeof(*longval));
+            break;
         case 'S':
             strval = va_arg(ap, char **);
             copy_bufs(&buf1, &buf2, &len1, &len2, &len, sizeof(len));
@@ -419,6 +481,12 @@  static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req,
             copy_bufs(&buf1, &buf2, &len1, &len2, *strval, len);
             (*strval)[len] = 0;
             break;
+        case 'D':
+            val = va_arg(ap, uint32_t *);
+            data = va_arg(ap, uint8_t *);
+            copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val));
+            copy_bufs(&buf1, &buf2, &len1, &len2, data, *val);
+            break;
         case 'Q':
             qval = va_arg(ap, uint8_t *);
             copy_bufs(&buf1, &buf2, &len1, &len2, qval, P9_QID_SIZE);
@@ -640,6 +708,115 @@  static int p9_create(struct dev_9pfs *dev, uint32_t fid, char *path,
     return ret;
 }
 
+static int p9_stat(struct dev_9pfs *dev, uint32_t fid, struct p9_stat *stat)
+{
+    struct req *req = get_free_req(dev);
+    int ret;
+
+    if ( !req )
+        return EAGAIN;
+
+    memset(stat, 0, sizeof(*stat));
+    req->cmd = P9_CMD_STAT;
+    send_9p(dev, req, "U", fid);
+    rcv_9p(dev, req, "uuUQUUULSSSSSUUU", &stat->size, &stat->type, &stat->dev,
+           stat->qid, &stat->mode, &stat->atime, &stat->mtime, &stat->length,
+           &stat->name, &stat->uid, &stat->gid, &stat->muid, &stat->extension,
+           &stat->n_uid, &stat->n_gid, &stat->n_muid);
+
+    ret = req->result;
+
+    put_free_req(dev, req);
+
+    return ret;
+}
+
+static int p9_read(struct dev_9pfs *dev, uint32_t fid, uint64_t offset,
+                   uint8_t *data, uint32_t len)
+{
+    struct req *req = get_free_req(dev);
+    int ret = 0;
+    uint32_t count, count_max;
+
+    if ( !req )
+    {
+        errno = EAGAIN;
+        return -1;
+    }
+    req->cmd = P9_CMD_READ;
+    count_max = dev->msize_max - (sizeof(struct p9_header) + sizeof(uint32_t));
+
+    while ( len )
+    {
+        count = len;
+        if ( count > count_max )
+            count = count_max;
+
+        send_9p(dev, req, "ULU", fid, offset, count);
+        rcv_9p(dev, req, "D", &count, data);
+
+        if ( !count )
+            break;
+        if ( req->result )
+        {
+            ret = -1;
+            errno = EIO;
+            printk("9pfs: read got error %d\n", req->result);
+            break;
+        }
+        ret += count;
+        offset += count;
+        data += count;
+        len -= count;
+    }
+
+    put_free_req(dev, req);
+
+    return ret;
+}
+
+static int p9_write(struct dev_9pfs *dev, uint32_t fid, uint64_t offset,
+                    const uint8_t *data, uint32_t len)
+{
+    struct req *req = get_free_req(dev);
+    int ret = 0;
+    uint32_t count, count_max;
+
+    if ( !req )
+    {
+        errno = EAGAIN;
+        return -1;
+    }
+    req->cmd = P9_CMD_WRITE;
+    count_max = dev->msize_max - (sizeof(struct p9_header) + sizeof(uint32_t) +
+                                  sizeof(uint64_t) + sizeof(uint32_t));
+
+    while ( len )
+    {
+        count = len;
+        if ( count > count_max )
+            count = count_max;
+
+        send_9p(dev, req, "ULD", fid, offset, count, data);
+        rcv_9p(dev, req, "U", &count);
+        if ( req->result )
+        {
+            ret = -1;
+            errno = EIO;
+            printk("9pfs: write got error %d\n", req->result);
+            break;
+        }
+        ret += count;
+        offset += count;
+        data += count;
+        len -= count;
+    }
+
+    put_free_req(dev, req);
+
+    return ret;
+}
+
 /*
  * Walk from root <steps> levels with the levels listed in <*paths> as a
  * sequence of names. Returns the number of steps not having been able to
@@ -731,6 +908,43 @@  static void intr_9pfs(evtchn_port_t port, struct pt_regs *regs, void *data)
     wake_up(&dev->waitq);
 }
 
+static int read_9pfs(struct file *file, void *buf, size_t nbytes)
+{
+    struct file_9pfs *f9pfs = file->filedata;
+    int ret;
+
+    ret = p9_read(f9pfs->dev, f9pfs->fid, file->offset, buf, nbytes);
+    if ( ret >= 0 )
+        file->offset += ret;
+
+    return ret;
+}
+
+static int write_9pfs(struct file *file, const void *buf, size_t nbytes)
+{
+    struct file_9pfs *f9pfs = file->filedata;
+    struct p9_stat stat;
+    int ret;
+
+    if ( f9pfs->append )
+    {
+        ret = p9_stat(f9pfs->dev, f9pfs->fid, &stat);
+        free_stat(&stat);
+        if ( ret )
+        {
+            errno = EIO;
+            return -1;
+        }
+        file->offset = stat.length;
+    }
+
+    ret = p9_write(f9pfs->dev, f9pfs->fid, file->offset, buf, nbytes);
+    if ( ret >= 0 )
+        file->offset += ret;
+
+    return ret;
+}
+
 static int close_9pfs(struct file *file)
 {
     struct file_9pfs *f9pfs = file->filedata;
@@ -1072,6 +1286,8 @@  void shutdown_9pfront(void *dev)
 
 static const struct file_ops ops_9pfs = {
     .name = "9pfs",
+    .read = read_9pfs,
+    .write = write_9pfs,
     .close = close_9pfs,
 };