Add the open() and close() support to the 9pfs frontend. This requires
to split the path name and to walk to the desired directory level.
Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- check path to be canonical
- avoid short read when walking the path
- fix get_fid() (Samuel Thibault)
- return EAGAIN if no free request got (Samuel Thibault)
V3:
- add check for "//" in path_canonical() (Samuel Thibault)
---
9pfront.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 322 insertions(+), 2 deletions(-)
diff --git a/9pfront.c b/9pfront.c
index 0b8d5461..fb2e5669 100644
--- a/9pfront.c
+++ b/9pfront.c
@@ -6,6 +6,7 @@
#include <mini-os/os.h>
#include <mini-os/lib.h>
#include <mini-os/events.h>
+#include <mini-os/fcntl.h>
#include <mini-os/gnttab.h>
#include <mini-os/semaphore.h>
#include <mini-os/wait.h>
@@ -52,13 +53,32 @@ struct dev_9pfs {
struct wait_queue_head waitq;
struct semaphore ring_out_sem;
struct semaphore ring_in_sem;
+
+ unsigned long long fid_mask; /* Bit mask for free fids. */
+};
+
+struct file_9pfs {
+ uint32_t fid;
+ struct dev_9pfs *dev;
+ bool append;
};
#define DEFAULT_9PFS_RING_ORDER 4
+/* P9 protocol commands (response is either cmd+1 or P9_CMD_ERROR). */
#define P9_CMD_VERSION 100
#define P9_CMD_ATTACH 104
#define P9_CMD_ERROR 107
+#define P9_CMD_WALK 110
+#define P9_CMD_OPEN 112
+#define P9_CMD_CREATE 114
+#define P9_CMD_CLUNK 120
+
+/* P9 protocol open flags. */
+#define P9_OREAD 0 /* read */
+#define P9_OWRITE 1 /* write */
+#define P9_ORDWR 2 /* read and write */
+#define P9_OTRUNC 16 /* or'ed in, truncate file first */
#define P9_QID_SIZE 13
@@ -69,10 +89,27 @@ struct p9_header {
} __attribute__((packed));
#define P9_VERSION "9P2000.u"
-#define P9_ROOT_FID ~0
+#define P9_ROOT_FID 0
static unsigned int ftype_9pfs;
+static unsigned int get_fid(struct dev_9pfs *dev)
+{
+ unsigned int fid;
+
+ fid = ffs(dev->fid_mask);
+ if ( fid )
+ dev->fid_mask &= ~(1ULL << (fid - 1));
+
+ return fid;
+}
+
+static void put_fid(struct dev_9pfs *dev, unsigned int fid)
+{
+ if ( fid )
+ dev->fid_mask |= 1ULL << (fid - 1);
+}
+
static struct req *get_free_req(struct dev_9pfs *dev)
{
struct req *req;
@@ -140,6 +177,9 @@ static void copy_from_ring(struct dev_9pfs *dev, void *data, unsigned int len)
* send_9p() and rcv_9p() are using a special format string for specifying
* the kind of data sent/expected. Each data item is represented by a single
* character:
+ * b: 1 byte unsigned integer (uint8_t)
+ * Only valid for sending.
+ * u: 2 byte unsigned integer (uint16_t)
* U: 4 byte unsigned integer (uint32_t)
* S: String (2 byte length + <length> characters)
* in the rcv_9p() case the data for string is allocated (length omitted,
@@ -153,7 +193,9 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...)
va_list ap, aq;
const char *f;
uint32_t intval;
+ uint16_t shortval;
uint16_t len;
+ uint8_t byte;
char *strval;
hdr.size = sizeof(hdr);
@@ -167,6 +209,14 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...)
{
switch ( *f )
{
+ case 'b':
+ hdr.size += 1;
+ byte = va_arg(aq, unsigned int);
+ break;
+ case 'u':
+ hdr.size += 2;
+ shortval = va_arg(aq, unsigned int);
+ break;
case 'U':
hdr.size += 4;
intval = va_arg(aq, unsigned int);
@@ -196,6 +246,14 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...)
{
switch ( *f )
{
+ case 'b':
+ byte = va_arg(ap, unsigned int);
+ copy_to_ring(dev, &byte, sizeof(byte));
+ break;
+ case 'u':
+ shortval = va_arg(ap, unsigned int);
+ copy_to_ring(dev, &shortval, sizeof(shortval));
+ break;
case 'U':
intval = va_arg(ap, unsigned int);
copy_to_ring(dev, &intval, sizeof(intval));
@@ -288,6 +346,7 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req,
char *str;
uint16_t len;
uint32_t err;
+ uint16_t *shortval;
uint32_t *val;
char **strval;
uint8_t *qval;
@@ -345,6 +404,10 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req,
{
switch ( *f )
{
+ case 'u':
+ shortval = va_arg(ap, uint16_t *);
+ copy_bufs(&buf1, &buf2, &len1, &len2, shortval, sizeof(*shortval));
+ break;
case 'U':
val = va_arg(ap, uint32_t *);
copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val));
@@ -486,6 +549,170 @@ static int p9_attach(struct dev_9pfs *dev)
return ret;
}
+static int p9_clunk(struct dev_9pfs *dev, uint32_t fid)
+{
+ struct req *req = get_free_req(dev);
+ int ret;
+
+ if ( !req )
+ return EAGAIN;
+
+ req->cmd = P9_CMD_CLUNK;
+ send_9p(dev, req, "U", fid);
+ rcv_9p(dev, req, "");
+ ret = req->result;
+
+ put_free_req(dev, req);
+
+ return ret;
+}
+
+static int p9_walk(struct dev_9pfs *dev, uint32_t fid, uint32_t newfid,
+ char *name)
+{
+ struct req *req = get_free_req(dev);
+ int ret;
+ uint16_t nqid;
+ uint8_t qid[P9_QID_SIZE];
+
+ if ( !req )
+ return EAGAIN;
+
+ req->cmd = P9_CMD_WALK;
+ if ( name[0] )
+ {
+ send_9p(dev, req, "UUuS", fid, newfid, 1, name);
+ rcv_9p(dev, req, "uQ", &nqid, qid);
+ }
+ else
+ {
+ send_9p(dev, req, "UUu", fid, newfid, 0);
+ rcv_9p(dev, req, "u", &nqid);
+ }
+
+ ret = req->result;
+
+ put_free_req(dev, req);
+
+ return ret;
+}
+
+static int p9_open(struct dev_9pfs *dev, uint32_t fid, uint8_t omode)
+{
+ struct req *req = get_free_req(dev);
+ int ret;
+ uint8_t qid[P9_QID_SIZE];
+ uint32_t iounit;
+
+ if ( !req )
+ return EAGAIN;
+
+ req->cmd = P9_CMD_OPEN;
+ send_9p(dev, req, "Ub", fid, omode);
+ rcv_9p(dev, req, "QU", qid, &iounit);
+
+ ret = req->result;
+
+ put_free_req(dev, req);
+
+ return ret;
+}
+
+static int p9_create(struct dev_9pfs *dev, uint32_t fid, char *path,
+ uint32_t mode, uint8_t omode)
+{
+ struct req *req = get_free_req(dev);
+ int ret;
+ uint8_t qid[P9_QID_SIZE];
+ uint32_t iounit;
+
+ if ( !req )
+ return EAGAIN;
+
+ req->cmd = P9_CMD_CREATE;
+ send_9p(dev, req, "USUbS", fid, path, mode, omode, "");
+ rcv_9p(dev, req, "QU", qid, &iounit);
+
+ ret = req->result;
+
+ 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
+ * walk, with <*paths> pointing at the name of the failing walk step.
+ * <fid> will be associated with the last successful walk step. Note that
+ * the first step should always succeed, as it is an empty walk in order
+ * to start at the root (needed for creating new files in root).
+ */
+static unsigned int walk_9pfs(struct dev_9pfs *dev, uint32_t fid,
+ unsigned int steps, char **paths)
+{
+ uint32_t curr_fid = P9_ROOT_FID;
+ int ret;
+
+ while ( steps-- )
+ {
+ ret = p9_walk(dev, curr_fid, fid, *paths);
+ if ( ret )
+ return steps + 1;
+ curr_fid = fid;
+ *paths += strlen(*paths) + 1;
+ }
+
+ return 0;
+}
+
+static unsigned int split_path(const char *pathname, char **split_ptr)
+{
+ unsigned int parts = 1;
+ char *p;
+
+ *split_ptr = strdup(pathname);
+
+ for ( p = strchr(*split_ptr, '/'); p; p = strchr(p + 1, '/') )
+ {
+ *p = 0;
+ parts++;
+ }
+
+ return parts;
+}
+
+static bool path_canonical(const char *pathname)
+{
+ unsigned int len = strlen(pathname);
+ const char *c;
+
+ /* Empty path is allowed. */
+ if ( !len )
+ return true;
+
+ /* No trailing '/'. */
+ if ( pathname[len - 1] == '/' )
+ return false;
+
+ /* No self or parent references. */
+ c = pathname;
+ while ( (c = strstr(c, "/.")) != NULL )
+ {
+ if ( c[2] == '.' )
+ c++;
+ if ( c[2] == 0 || c[2] == '/' )
+ return false;
+ c += 2;
+ }
+
+ /* No "//". */
+ if ( strstr(pathname, "//") )
+ return false;
+
+ return true;
+}
+
static int connect_9pfs(struct dev_9pfs *dev)
{
int ret;
@@ -504,10 +731,101 @@ static void intr_9pfs(evtchn_port_t port, struct pt_regs *regs, void *data)
wake_up(&dev->waitq);
}
+static int close_9pfs(struct file *file)
+{
+ struct file_9pfs *f9pfs = file->filedata;
+
+ if ( f9pfs->fid != P9_ROOT_FID )
+ {
+ p9_clunk(f9pfs->dev, f9pfs->fid);
+ put_fid(f9pfs->dev, f9pfs->fid);
+ }
+
+ free(f9pfs);
+
+ return 0;
+}
+
static int open_9pfs(struct mount_point *mnt, const char *pathname, int flags,
mode_t mode)
{
- errno = ENOSYS;
+ int fd;
+ char *path = NULL;
+ char *p;
+ struct file *file;
+ struct file_9pfs *f9pfs;
+ uint16_t nwalk;
+ uint8_t omode;
+ int ret;
+
+ if ( !path_canonical(pathname) )
+ return EINVAL;
+
+ f9pfs = calloc(1, sizeof(*f9pfs));
+ f9pfs->dev = mnt->dev;
+ f9pfs->fid = P9_ROOT_FID;
+
+ fd = alloc_fd(ftype_9pfs);
+ file = get_file_from_fd(fd);
+ file->filedata = f9pfs;
+
+ switch ( flags & O_ACCMODE )
+ {
+ case O_RDONLY:
+ omode = P9_OREAD;
+ break;
+ case O_WRONLY:
+ omode = P9_OWRITE;
+ break;
+ case O_RDWR:
+ omode = P9_ORDWR;
+ break;
+ default:
+ ret = EINVAL;
+ goto err;
+ }
+
+ if ( flags & O_TRUNC )
+ omode |= P9_OTRUNC;
+ f9pfs->append = flags & O_APPEND;
+
+ nwalk = split_path(pathname, &path);
+
+ f9pfs->fid = get_fid(mnt->dev);
+ if ( !f9pfs->fid )
+ {
+ ret = ENFILE;
+ goto err;
+ }
+ p = path;
+ nwalk = walk_9pfs(mnt->dev, f9pfs->fid, nwalk, &p);
+ if ( nwalk )
+ {
+ if ( nwalk > 1 || !(flags & O_CREAT) )
+ {
+ ret = ENOENT;
+ goto err;
+ }
+
+ ret = p9_create(mnt->dev, f9pfs->fid, p, mode, omode);
+ if ( ret )
+ goto err;
+ goto out;
+ }
+
+ ret = p9_open(mnt->dev, f9pfs->fid, omode);
+ if ( ret )
+ goto err;
+
+ out:
+ free(path);
+
+ return fd;
+
+ err:
+ free(path);
+ close(fd);
+ errno = ret;
return -1;
}
@@ -552,6 +870,7 @@ void *init_9pfront(unsigned int id, const char *mnt)
init_waitqueue_head(&dev->waitq);
init_SEMAPHORE(&dev->ring_out_sem, 1);
init_SEMAPHORE(&dev->ring_in_sem, 1);
+ dev->fid_mask = ~0ULL;
for ( i = 0; i < N_REQS; i++ )
{
@@ -753,6 +1072,7 @@ void shutdown_9pfront(void *dev)
static const struct file_ops ops_9pfs = {
.name = "9pfs",
+ .close = close_9pfs,
};
__attribute__((constructor))
--
2.35.3
Juergen Gross, le lun. 13 févr. 2023 09:44:11 +0100, a ecrit: > Add the open() and close() support to the 9pfs frontend. This requires > to split the path name and to walk to the desired directory level. > > Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > --- > V2: > - check path to be canonical > - avoid short read when walking the path > - fix get_fid() (Samuel Thibault) > - return EAGAIN if no free request got (Samuel Thibault) > V3: > - add check for "//" in path_canonical() (Samuel Thibault) > --- > 9pfront.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 322 insertions(+), 2 deletions(-) > > diff --git a/9pfront.c b/9pfront.c > index 0b8d5461..fb2e5669 100644 > --- a/9pfront.c > +++ b/9pfront.c > @@ -6,6 +6,7 @@ > #include <mini-os/os.h> > #include <mini-os/lib.h> > #include <mini-os/events.h> > +#include <mini-os/fcntl.h> > #include <mini-os/gnttab.h> > #include <mini-os/semaphore.h> > #include <mini-os/wait.h> > @@ -52,13 +53,32 @@ struct dev_9pfs { > struct wait_queue_head waitq; > struct semaphore ring_out_sem; > struct semaphore ring_in_sem; > + > + unsigned long long fid_mask; /* Bit mask for free fids. */ > +}; > + > +struct file_9pfs { > + uint32_t fid; > + struct dev_9pfs *dev; > + bool append; > }; > > #define DEFAULT_9PFS_RING_ORDER 4 > > +/* P9 protocol commands (response is either cmd+1 or P9_CMD_ERROR). */ > #define P9_CMD_VERSION 100 > #define P9_CMD_ATTACH 104 > #define P9_CMD_ERROR 107 > +#define P9_CMD_WALK 110 > +#define P9_CMD_OPEN 112 > +#define P9_CMD_CREATE 114 > +#define P9_CMD_CLUNK 120 > + > +/* P9 protocol open flags. */ > +#define P9_OREAD 0 /* read */ > +#define P9_OWRITE 1 /* write */ > +#define P9_ORDWR 2 /* read and write */ > +#define P9_OTRUNC 16 /* or'ed in, truncate file first */ > > #define P9_QID_SIZE 13 > > @@ -69,10 +89,27 @@ struct p9_header { > } __attribute__((packed)); > > #define P9_VERSION "9P2000.u" > -#define P9_ROOT_FID ~0 > +#define P9_ROOT_FID 0 > > static unsigned int ftype_9pfs; > > +static unsigned int get_fid(struct dev_9pfs *dev) > +{ > + unsigned int fid; > + > + fid = ffs(dev->fid_mask); > + if ( fid ) > + dev->fid_mask &= ~(1ULL << (fid - 1)); > + > + return fid; > +} > + > +static void put_fid(struct dev_9pfs *dev, unsigned int fid) > +{ > + if ( fid ) > + dev->fid_mask |= 1ULL << (fid - 1); > +} > + > static struct req *get_free_req(struct dev_9pfs *dev) > { > struct req *req; > @@ -140,6 +177,9 @@ static void copy_from_ring(struct dev_9pfs *dev, void *data, unsigned int len) > * send_9p() and rcv_9p() are using a special format string for specifying > * the kind of data sent/expected. Each data item is represented by a single > * character: > + * b: 1 byte unsigned integer (uint8_t) > + * Only valid for sending. > + * u: 2 byte unsigned integer (uint16_t) > * U: 4 byte unsigned integer (uint32_t) > * S: String (2 byte length + <length> characters) > * in the rcv_9p() case the data for string is allocated (length omitted, > @@ -153,7 +193,9 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) > va_list ap, aq; > const char *f; > uint32_t intval; > + uint16_t shortval; > uint16_t len; > + uint8_t byte; > char *strval; > > hdr.size = sizeof(hdr); > @@ -167,6 +209,14 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) > { > switch ( *f ) > { > + case 'b': > + hdr.size += 1; > + byte = va_arg(aq, unsigned int); > + break; > + case 'u': > + hdr.size += 2; > + shortval = va_arg(aq, unsigned int); > + break; > case 'U': > hdr.size += 4; > intval = va_arg(aq, unsigned int); > @@ -196,6 +246,14 @@ static void send_9p(struct dev_9pfs *dev, struct req *req, const char *fmt, ...) > { > switch ( *f ) > { > + case 'b': > + byte = va_arg(ap, unsigned int); > + copy_to_ring(dev, &byte, sizeof(byte)); > + break; > + case 'u': > + shortval = va_arg(ap, unsigned int); > + copy_to_ring(dev, &shortval, sizeof(shortval)); > + break; > case 'U': > intval = va_arg(ap, unsigned int); > copy_to_ring(dev, &intval, sizeof(intval)); > @@ -288,6 +346,7 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req, > char *str; > uint16_t len; > uint32_t err; > + uint16_t *shortval; > uint32_t *val; > char **strval; > uint8_t *qval; > @@ -345,6 +404,10 @@ static void rcv_9p_copy(struct dev_9pfs *dev, struct req *req, > { > switch ( *f ) > { > + case 'u': > + shortval = va_arg(ap, uint16_t *); > + copy_bufs(&buf1, &buf2, &len1, &len2, shortval, sizeof(*shortval)); > + break; > case 'U': > val = va_arg(ap, uint32_t *); > copy_bufs(&buf1, &buf2, &len1, &len2, val, sizeof(*val)); > @@ -486,6 +549,170 @@ static int p9_attach(struct dev_9pfs *dev) > return ret; > } > > +static int p9_clunk(struct dev_9pfs *dev, uint32_t fid) > +{ > + struct req *req = get_free_req(dev); > + int ret; > + > + if ( !req ) > + return EAGAIN; > + > + req->cmd = P9_CMD_CLUNK; > + send_9p(dev, req, "U", fid); > + rcv_9p(dev, req, ""); > + ret = req->result; > + > + put_free_req(dev, req); > + > + return ret; > +} > + > +static int p9_walk(struct dev_9pfs *dev, uint32_t fid, uint32_t newfid, > + char *name) > +{ > + struct req *req = get_free_req(dev); > + int ret; > + uint16_t nqid; > + uint8_t qid[P9_QID_SIZE]; > + > + if ( !req ) > + return EAGAIN; > + > + req->cmd = P9_CMD_WALK; > + if ( name[0] ) > + { > + send_9p(dev, req, "UUuS", fid, newfid, 1, name); > + rcv_9p(dev, req, "uQ", &nqid, qid); > + } > + else > + { > + send_9p(dev, req, "UUu", fid, newfid, 0); > + rcv_9p(dev, req, "u", &nqid); > + } > + > + ret = req->result; > + > + put_free_req(dev, req); > + > + return ret; > +} > + > +static int p9_open(struct dev_9pfs *dev, uint32_t fid, uint8_t omode) > +{ > + struct req *req = get_free_req(dev); > + int ret; > + uint8_t qid[P9_QID_SIZE]; > + uint32_t iounit; > + > + if ( !req ) > + return EAGAIN; > + > + req->cmd = P9_CMD_OPEN; > + send_9p(dev, req, "Ub", fid, omode); > + rcv_9p(dev, req, "QU", qid, &iounit); > + > + ret = req->result; > + > + put_free_req(dev, req); > + > + return ret; > +} > + > +static int p9_create(struct dev_9pfs *dev, uint32_t fid, char *path, > + uint32_t mode, uint8_t omode) > +{ > + struct req *req = get_free_req(dev); > + int ret; > + uint8_t qid[P9_QID_SIZE]; > + uint32_t iounit; > + > + if ( !req ) > + return EAGAIN; > + > + req->cmd = P9_CMD_CREATE; > + send_9p(dev, req, "USUbS", fid, path, mode, omode, ""); > + rcv_9p(dev, req, "QU", qid, &iounit); > + > + ret = req->result; > + > + 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 > + * walk, with <*paths> pointing at the name of the failing walk step. > + * <fid> will be associated with the last successful walk step. Note that > + * the first step should always succeed, as it is an empty walk in order > + * to start at the root (needed for creating new files in root). > + */ > +static unsigned int walk_9pfs(struct dev_9pfs *dev, uint32_t fid, > + unsigned int steps, char **paths) > +{ > + uint32_t curr_fid = P9_ROOT_FID; > + int ret; > + > + while ( steps-- ) > + { > + ret = p9_walk(dev, curr_fid, fid, *paths); > + if ( ret ) > + return steps + 1; > + curr_fid = fid; > + *paths += strlen(*paths) + 1; > + } > + > + return 0; > +} > + > +static unsigned int split_path(const char *pathname, char **split_ptr) > +{ > + unsigned int parts = 1; > + char *p; > + > + *split_ptr = strdup(pathname); > + > + for ( p = strchr(*split_ptr, '/'); p; p = strchr(p + 1, '/') ) > + { > + *p = 0; > + parts++; > + } > + > + return parts; > +} > + > +static bool path_canonical(const char *pathname) > +{ > + unsigned int len = strlen(pathname); > + const char *c; > + > + /* Empty path is allowed. */ > + if ( !len ) > + return true; > + > + /* No trailing '/'. */ > + if ( pathname[len - 1] == '/' ) > + return false; > + > + /* No self or parent references. */ > + c = pathname; > + while ( (c = strstr(c, "/.")) != NULL ) > + { > + if ( c[2] == '.' ) > + c++; > + if ( c[2] == 0 || c[2] == '/' ) > + return false; > + c += 2; > + } > + > + /* No "//". */ > + if ( strstr(pathname, "//") ) > + return false; > + > + return true; > +} > + > static int connect_9pfs(struct dev_9pfs *dev) > { > int ret; > @@ -504,10 +731,101 @@ static void intr_9pfs(evtchn_port_t port, struct pt_regs *regs, void *data) > wake_up(&dev->waitq); > } > > +static int close_9pfs(struct file *file) > +{ > + struct file_9pfs *f9pfs = file->filedata; > + > + if ( f9pfs->fid != P9_ROOT_FID ) > + { > + p9_clunk(f9pfs->dev, f9pfs->fid); > + put_fid(f9pfs->dev, f9pfs->fid); > + } > + > + free(f9pfs); > + > + return 0; > +} > + > static int open_9pfs(struct mount_point *mnt, const char *pathname, int flags, > mode_t mode) > { > - errno = ENOSYS; > + int fd; > + char *path = NULL; > + char *p; > + struct file *file; > + struct file_9pfs *f9pfs; > + uint16_t nwalk; > + uint8_t omode; > + int ret; > + > + if ( !path_canonical(pathname) ) > + return EINVAL; > + > + f9pfs = calloc(1, sizeof(*f9pfs)); > + f9pfs->dev = mnt->dev; > + f9pfs->fid = P9_ROOT_FID; > + > + fd = alloc_fd(ftype_9pfs); > + file = get_file_from_fd(fd); > + file->filedata = f9pfs; > + > + switch ( flags & O_ACCMODE ) > + { > + case O_RDONLY: > + omode = P9_OREAD; > + break; > + case O_WRONLY: > + omode = P9_OWRITE; > + break; > + case O_RDWR: > + omode = P9_ORDWR; > + break; > + default: > + ret = EINVAL; > + goto err; > + } > + > + if ( flags & O_TRUNC ) > + omode |= P9_OTRUNC; > + f9pfs->append = flags & O_APPEND; > + > + nwalk = split_path(pathname, &path); > + > + f9pfs->fid = get_fid(mnt->dev); > + if ( !f9pfs->fid ) > + { > + ret = ENFILE; > + goto err; > + } > + p = path; > + nwalk = walk_9pfs(mnt->dev, f9pfs->fid, nwalk, &p); > + if ( nwalk ) > + { > + if ( nwalk > 1 || !(flags & O_CREAT) ) > + { > + ret = ENOENT; > + goto err; > + } > + > + ret = p9_create(mnt->dev, f9pfs->fid, p, mode, omode); > + if ( ret ) > + goto err; > + goto out; > + } > + > + ret = p9_open(mnt->dev, f9pfs->fid, omode); > + if ( ret ) > + goto err; > + > + out: > + free(path); > + > + return fd; > + > + err: > + free(path); > + close(fd); > + errno = ret; > > return -1; > } > @@ -552,6 +870,7 @@ void *init_9pfront(unsigned int id, const char *mnt) > init_waitqueue_head(&dev->waitq); > init_SEMAPHORE(&dev->ring_out_sem, 1); > init_SEMAPHORE(&dev->ring_in_sem, 1); > + dev->fid_mask = ~0ULL; > > for ( i = 0; i < N_REQS; i++ ) > { > @@ -753,6 +1072,7 @@ void shutdown_9pfront(void *dev) > > static const struct file_ops ops_9pfs = { > .name = "9pfs", > + .close = close_9pfs, > }; > > __attribute__((constructor)) > -- > 2.35.3 > -- Samuel --- Pour une évaluation indépendante, transparente et rigoureuse ! Je soutiens la Commission d'Évaluation de l'Inria.
© 2016 - 2024 Red Hat, Inc.