-config LIBPOSIX_FD
+menuconfig LIBPOSIX_FD
bool "posix-fd: Open file descriptions"
select LIBUKFILE
select LIBUKLOCK
select LIBUKLOCK_MUTEX
+
+if LIBPOSIX_FD
+
+config LIBPOSIX_FD_HEAPOFD
+ bool "Heap-allocated open file descriptions"
+ select LIBUKALLOC
+
+endif
#include <uk/essentials.h>
#include <uk/file.h>
#include <uk/mutex.h>
+
+#if CONFIG_LIBPOSIX_FD_HEAPOFD
+#include <uk/alloc.h>
#include <uk/refcount.h>
+#endif /* CONFIG_LIBPOSIX_FD_HEAPOFD */
/* Open file description */
struct uk_ofile {
const struct uk_file *file;
- unsigned int mode;
- __atomic refcnt;
size_t pos; /* Current file read/write offset position */
struct uk_mutex lock; /* Lock for modifying open file state */
+ unsigned int mode;
+#if CONFIG_LIBPOSIX_FD_HEAPOFD
+ __atomic refcnt;
+#endif /* CONFIG_LIBPOSIX_FD_HEAPOFD */
char name[]; /* Name of open file description; driver dependent */
/* Filesystem-backed files should be named after the path they were
* opened with. Pseudo-files should be named something descriptive.
void uk_ofile_init(struct uk_ofile *of,
const struct uk_file *f, unsigned int mode)
{
+#if CONFIG_LIBPOSIX_FD_HEAPOFD
uk_refcount_init(&of->refcnt, 1);
+#endif /* CONFIG_LIBPOSIX_FD_HEAPOFD */
uk_mutex_init(&of->lock);
of->file = f;
- of->mode = mode;
+ /* O_CLOEXEC is uniquely not a file description flag; ignore */
+ of->mode = mode & ~O_CLOEXEC;
of->pos = 0;
}
-/**
- * Acquire a reference on open file description `of`.
- *
- * @param of Open file description
- */
-static inline
-void uk_ofile_acquire(struct uk_ofile *of)
-{
- uk_refcount_acquire(&of->refcnt);
-}
-
-/**
- * Release a reference held on open file description `of`.
- *
- * Do not call directly unless you are prepared to handle cleanup after the last
- * reference is dropped. Instead use the release function provided by the lib
- * where you got the open file reference from.
- *
- * @param of Open file description
- *
- * @return
- * == 0: There are remaining references held
- * != 0: The last reference has just been released
- */
-static inline
-int uk_ofile_release(struct uk_ofile *of)
-{
- return uk_refcount_release(&of->refcnt);
-}
-
-
/* Mode bits from fcntl.h that open files are interested in */
#define UKFD_MODE_MASK \
(O_WRONLY|O_RDWR|O_NONBLOCK|O_APPEND|O_DIRECT|O_SYNC|O_DSYNC)
#define UKFD_POLLIN (EPOLLIN|EPOLLRDNORM|EPOLLRDBAND)
#define UKFD_POLLOUT (EPOLLOUT|EPOLLWRNORM|EPOLLWRBAND)
+/* Heap-allocated open file descriptions */
+
+#if CONFIG_LIBPOSIX_FD_HEAPOFD
+
+/**
+ * Allocate heap memory for an open file description with name of length `len`
+ * and initialize its fields.
+ *
+ * The caller is responsible for populating the .name field.
+ *
+ * @return
+ * != NULL: Success
+ * == NULL: Failed to allocate memory
+ */
+static inline
+struct uk_ofile *uk_ofile_new(const struct uk_file *f, unsigned int mode,
+ size_t len)
+{
+ struct uk_ofile *ret = uk_malloc(uk_alloc_get_default(),
+ UKFD_OFILE_SIZE(len));
+
+ if (unlikely(!ret))
+ return NULL;
+
+ if (len)
+ mode |= UKFD_O_NAMED;
+ uk_file_acquire(f);
+ uk_ofile_init(ret, f, mode);
+ return ret;
+}
+
+/**
+ * Free a heap-allocated open file description `of`.
+ */
+static inline
+void uk_ofile_free(struct uk_ofile *of)
+{
+ return uk_free(uk_alloc_get_default(), of);
+}
+
+/**
+ * Acquire a reference on open file description `of`.
+ *
+ * @param of Open file description
+ */
+static inline
+void uk_ofile_acquire(struct uk_ofile *of)
+{
+ uk_refcount_acquire(&of->refcnt);
+}
+
+/**
+ * Release a reference held on open file description `of`, freeing resources
+ * if needed.
+ */
+static inline
+void uk_ofile_release(struct uk_ofile *of)
+{
+ const int last_ref = uk_refcount_release(&of->refcnt);
+
+ if (unlikely(last_ref)) {
+ uk_file_release(of->file);
+ uk_ofile_free(of);
+ }
+}
+
+#endif /* CONFIG_LIBPOSIX_FD_HEAPOFD */
+
#endif /* __UK_POSIX_FD_H__ */
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_preadv2(sf.ofile, iov, iovcnt, offset, flags);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_preadv(sf.ofile, iov, iovcnt, offset);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_pread(sf.ofile, buf, count, offset);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_readv(sf.ofile, iov, iovcnt);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_read(sf.ofile, buf, count);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_pwritev2(sf.ofile, iov, iovcnt, offset, flags);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_pwritev(sf.ofile, iov, iovcnt, offset);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_pwrite(sf.ofile, buf, count, offset);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_writev(sf.ofile, iov, iovcnt);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_write(sf.ofile, buf, count);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_lseek(sf.ofile, offset, whence);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_fstat(sf.ofile, statbuf);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_fchmod(sf.ofile, mode);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_fchown(sf.ofile, owner, group);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_fsync(sf.ofile);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_fdatasync(sf.ofile);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_ftruncate(sf.ofile, len);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_fallocate(sf.ofile, mode, off, len);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_fadvise(sf.ofile, off, len, advice);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_fcntl(sf.ofile, cmd, arg);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
switch (uk_fdtab_shim_get(fd, &sf)) {
case UK_SHIM_OFILE:
r = uk_sys_ioctl(sf.ofile, request, arg);
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
break;
#if CONFIG_LIBVFSCORE
case UK_SHIM_LEGACY:
select LIBUKATOMIC
select LIBUKFILE
select LIBPOSIX_FD
+ select LIBPOSIX_FD_HEAPOFD
if LIBPOSIX_FDTAB
config LIBPOSIX_FDTAB_MAXFDS
};
}
-/* struct uk_ofile allocation & refcounting */
-static inline struct uk_ofile *ofile_new(struct uk_fdtab *tab,
- const struct uk_file *f,
- unsigned int mode,
- size_t len)
-{
- struct uk_ofile *of;
-
- of = uk_malloc(tab->alloc, UKFD_OFILE_SIZE(len));
- if (of) {
- if (len)
- mode |= UKFD_O_NAMED;
- uk_ofile_init(of, f, mode);
- }
- return of;
-}
-static inline void ofile_del(struct uk_fdtab *tab, struct uk_ofile *of)
-{
- uk_free(tab->alloc, of);
-}
-
-static inline void ofile_acq(struct uk_ofile *of)
-{
- uk_ofile_acquire(of);
-}
-static inline void ofile_rel(struct uk_fdtab *tab, struct uk_ofile *of)
-{
- if (uk_ofile_release(of)) {
- uk_file_release(of->file);
- ofile_del(tab, of);
- }
-}
-
-#if CONFIG_LIBPOSIX_FDTAB_LEGACY_SHIM
-
static inline void file_acq(void *p, int flags __maybe_unused)
{
#if CONFIG_LIBVFSCORE
fhold((struct vfscore_file *)p);
else
#endif /* CONFIG_LIBVFSCORE */
- ofile_acq((struct uk_ofile *)p);
+ uk_ofile_acquire((struct uk_ofile *)p);
}
-static inline
-void file_rel(struct uk_fdtab *tab, void *p, int flags __maybe_unused)
+static inline void file_rel(void *p, int flags __maybe_unused)
{
#if CONFIG_LIBVFSCORE
if (flags & UK_FDTAB_VFSCORE)
fdrop((struct vfscore_file *)p);
else
#endif /* CONFIG_LIBVFSCORE */
- ofile_rel(tab, (struct uk_ofile *)p);
+ uk_ofile_release((struct uk_ofile *)p);
}
-#else /* !CONFIG_LIBPOSIX_FDTAB_LEGACY_SHIM */
-
-#define file_acq(p, f) ofile_acq((struct uk_ofile *)(p))
-#define file_rel(t, p, f) ofile_rel((t), (struct uk_ofile *)(p))
-
-#endif /* !CONFIG_LIBPOSIX_FDTAB_LEGACY_SHIM */
-
/* Ops */
-struct uk_ofile *uk_fdtab_new_desc(const struct uk_file *f, unsigned int mode,
- size_t len)
-{
- struct uk_ofile *of;
-
- of = ofile_new(active_fdtab, f, mode & ~O_CLOEXEC, len);
- if (of)
- uk_file_acquire(f);
- return of;
-}
-
int uk_fdtab_open_desc(struct uk_ofile *of, unsigned int mode)
{
int fd;
if (!name)
len = 0;
- of = uk_fdtab_new_desc(f, mode, len);
+ of = uk_ofile_new(f, mode, len);
if (unlikely(!of))
return -ENOMEM;
if (len) {
/* Place the file in fdtab */
fd = uk_fdtab_open_desc(of, mode);
if (unlikely(fd < 0))
- ofile_rel(active_fdtab, of);
+ uk_ofile_release(of);
return fd;
}
{
struct uk_ofile *of = (struct uk_ofile *)v.p;
- ofile_acq(of);
+ uk_ofile_acquire(of);
uk_fmap_critical_put(fmap, fd, p);
out->ofile = of;
return UK_SHIM_OFILE;
#if CONFIG_LIBPOSIX_FDTAB_LEGACY_SHIM
/* Report legacy files as not present if called through new API */
if (v.p && v.flags & UK_FDTAB_VFSCORE) {
- file_rel(active_fdtab, v.p, v.flags);
+ file_rel(v.p, v.flags);
return NULL;
}
#endif /* CONFIG_LIBPOSIX_FDTAB_LEGACY_SHIM */
return (struct uk_ofile *)v.p;
}
-void uk_fdtab_ret(struct uk_ofile *of)
-{
- UK_ASSERT(of);
- ofile_rel(active_fdtab, of);
-}
-
static void fdtab_cleanup(struct uk_fdtab *tab, int all)
{
struct uk_fmap *fmap = &tab->fmap;
pp = uk_fmap_take(fmap, i);
UK_ASSERT(p == pp);
- file_rel(tab, v.p, v.flags);
+ file_rel(v.p, v.flags);
}
}
}
if (!p)
return -EBADF;
v = fdtab_decode(p);
- file_rel(active_fdtab, v.p, v.flags);
+ file_rel(v.p, v.flags);
return 0;
}
if (prevp) {
struct fdval prevv = fdtab_decode(prevp);
- file_rel(active_fdtab, prevv.p, prevv.flags);
+ file_rel(prevv.p, prevv.flags);
}
return newfd;
}
newent = fdtab_encode(dup.p, dup.flags);
fd = uk_fmap_put(&active_fdtab->fmap, newent, min);
if (fd >= UK_FDTAB_SIZE) {
- file_rel(active_fdtab, dup.p, dup.flags);
+ file_rel(dup.p, dup.flags);
return -ENFILE;
}
return fd;
int uk_fdtab_open_named(const struct uk_file *f, unsigned int mode,
const char *name, size_t len);
-/**
- * Create a new open file description for file `f` with `mode` and optional
- * name, without associating it with a file descriptor.
- *
- * The caller is responsible for filling in the .name field of returned open
- * file descriptions before use.
- * The returned open file description must be released with `uk_fdtab_ret` when
- * caller is finished with it.
- * Open file descriptions created in this way may be used as-is, or later
- * associated with an fd with `uk_fdtab_open_desc`.
- *
- * @param f
- * File to open
- * @param mode
- * Mode flags to apply on the new open file description
- * @param len
- * If > 0, allocate space for a file name of length `len` (excluding NUL)
- * @return
- * The new open file description, or NULL if no memory is available
- */
-struct uk_ofile *uk_fdtab_new_desc(const struct uk_file *f, unsigned int mode,
- size_t len);
-
/**
* Associate a file descriptor to an existing open file description.
*
* This call consumes the `of` reference. The caller MUST NOT use or release
* `of` after this call returns successfully.
* In case of error, the reference is left untouched.
- * The open file description must have been opened by this fdtab, through either
- * `uk_fdtab_new_desc` or `uk_fdtab_open*`.
*
* @param of
* Open file description to associate fd with
*/
struct uk_ofile *uk_fdtab_get(int fd);
-/**
- * Returns a reference to an open file when done using it.
- *
- * @param of
- * Reference to the open file description to be returned
- */
-void uk_fdtab_ret(struct uk_ofile *of);
-
/**
* Sets flags on file descriptor. Currently only supports O_CLOEXEC.
*
fdrop(sf.vfile);
else
#endif /* CONFIG_LIBVFSCORE */
- uk_fdtab_ret(sf.ofile);
+ uk_ofile_release(sf.ofile);
return ret;
}
if (unlikely(!of))
return -EBADF;
r = uk_sys_epoll_ctl(of->file, op, fd, event);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
return r;
}
return -EBADF;
r = uk_sys_epoll_pwait2(of->file, events, maxevents,
timeout, sigmask, sigsetsize);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
return r;
}
return -EBADF;
r = uk_sys_epoll_pwait(of->file, events, maxevents,
timeout, sigmask, sigsetsize);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
return r;
}
return -EBADF;
r = uk_sys_epoll_pwait(of->file, events, maxevents,
timeout, NULL, 0);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
return r;
}
if (unlikely(!of))
return ERR2PTR(-EBADF);
if (unlikely(of->file->vol != POSIX_SOCKET_VOLID)) {
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
return ERR2PTR(-ENOTSOCK);
}
return of;
mode = of->mode;
ret = uk_sys_accept(of->file, _SHOULD_BLOCK(mode),
addr, addr_len, flags);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret >= 0)
uk_file_wlock(of->file);
ret = posix_socket_bind(of->file, addr, addr_len);
uk_file_wunlock(of->file);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret) {
uk_file_wlock(of->file);
ret = posix_socket_shutdown(of->file, how);
uk_file_wunlock(of->file);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret)
uk_file_rlock(of->file);
ret = posix_socket_getpeername(of->file, addr, addr_len);
uk_file_runlock(of->file);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret)
uk_file_rlock(of->file);
ret = posix_socket_getsockname(of->file, addr, addr_len);
uk_file_runlock(of->file);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret)
uk_file_rlock(of->file);
ret = posix_socket_getsockopt(of->file, level, optname, optval, optlen);
uk_file_runlock(of->file);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret)
uk_file_rlock(of->file);
ret = posix_socket_setsockopt(of->file, level, optname, optval, optlen);
uk_file_runlock(of->file);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret)
&ret, &_opsz);
uk_file_runlock(of->file);
}
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret && ret != -EINPROGRESS) {
uk_file_wlock(of->file);
ret = posix_socket_listen(of->file, backlog);
uk_file_wunlock(of->file);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret) {
break;
(void)uk_file_poll(of->file, UKFD_POLLIN);
}
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret < 0 && ret != -EAGAIN)
break;
(void)uk_file_poll(of->file, UKFD_POLLIN);
}
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret < 0 && ret != -EAGAIN)
break;
(void)uk_file_poll(of->file, UKFD_POLLOUT);
}
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret < 0 && ret != -EAGAIN)
break;
(void)uk_file_poll(of->file, UKFD_POLLOUT);
}
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
out:
if (ret < 0 && ret != -EAGAIN)
if (unlikely(!of))
return -EBADF;
r = uk_sys_timerfd_settime(of->file, flags, new_value, old_value);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
return r;
}
if (unlikely(!of))
return -EBADF;
r = uk_sys_timerfd_gettime(of->file, curr_value);
- uk_fdtab_ret(of);
+ uk_ofile_release(of);
return r;
}
#endif /* CONFIG_LIBPOSIX_FDTAB */