1e21c39aaSAnton Nayshtut /* SPDX-License-Identifier: BSD-3-Clause 2e21c39aaSAnton Nayshtut * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3e21c39aaSAnton Nayshtut */ 4e21c39aaSAnton Nayshtut #include "spdk/stdinc.h" 5e21c39aaSAnton Nayshtut #include "spdk/event.h" 6e21c39aaSAnton Nayshtut #include "spdk/log.h" 7e21c39aaSAnton Nayshtut #include "spdk/string.h" 8e21c39aaSAnton Nayshtut #include "spdk/config.h" 9e21c39aaSAnton Nayshtut #include "spdk/util.h" 10e21c39aaSAnton Nayshtut #include "spdk/thread.h" 11e21c39aaSAnton Nayshtut #include "aio_mgr.h" 12e21c39aaSAnton Nayshtut #include "fsdev_aio.h" 13e21c39aaSAnton Nayshtut 14e21c39aaSAnton Nayshtut #define IO_STATUS_ASYNC INT_MIN 15e21c39aaSAnton Nayshtut 16e21c39aaSAnton Nayshtut #ifndef UNUSED 17e21c39aaSAnton Nayshtut #define UNUSED(x) (void)(x) 18e21c39aaSAnton Nayshtut #endif 19e21c39aaSAnton Nayshtut 20e21c39aaSAnton Nayshtut /* See https://libfuse.github.io/doxygen/structfuse__conn__info.html */ 21e21c39aaSAnton Nayshtut #define MAX_BACKGROUND (100) 22e21c39aaSAnton Nayshtut #define TIME_GRAN (1) 23e21c39aaSAnton Nayshtut #define MAX_AIOS 256 24e21c39aaSAnton Nayshtut #define DEFAULT_WRITEBACK_CACHE true 25e21c39aaSAnton Nayshtut #define DEFAULT_MAX_WRITE 0x00020000 26e21c39aaSAnton Nayshtut #define DEFAULT_XATTR_ENABLED false 2792108e0aSYoray Zack #define DEFAULT_SKIP_RW false 28e21c39aaSAnton Nayshtut #define DEFAULT_TIMEOUT_MS 0 /* to prevent the attribute caching */ 29e21c39aaSAnton Nayshtut 30e21c39aaSAnton Nayshtut #ifdef SPDK_CONFIG_HAVE_STRUCT_STAT_ST_ATIM 31e21c39aaSAnton Nayshtut /* Linux */ 32e21c39aaSAnton Nayshtut #define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec) 33e21c39aaSAnton Nayshtut #define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec) 34e21c39aaSAnton Nayshtut #define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec) 35e21c39aaSAnton Nayshtut #define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val) 36e21c39aaSAnton Nayshtut #define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctim.tv_nsec = (val) 37e21c39aaSAnton Nayshtut #define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val) 38e21c39aaSAnton Nayshtut #elif defined(SPDK_CONFIG_HAVE_STRUCT_STAT_ST_ATIMESPEC) 39e21c39aaSAnton Nayshtut /* FreeBSD */ 40e21c39aaSAnton Nayshtut #define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec) 41e21c39aaSAnton Nayshtut #define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec) 42e21c39aaSAnton Nayshtut #define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec) 43e21c39aaSAnton Nayshtut #define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val) 44e21c39aaSAnton Nayshtut #define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctimespec.tv_nsec = (val) 45e21c39aaSAnton Nayshtut #define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val) 46e21c39aaSAnton Nayshtut #else 47e21c39aaSAnton Nayshtut #define ST_ATIM_NSEC(stbuf) 0 48e21c39aaSAnton Nayshtut #define ST_CTIM_NSEC(stbuf) 0 49e21c39aaSAnton Nayshtut #define ST_MTIM_NSEC(stbuf) 0 50e21c39aaSAnton Nayshtut #define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0) 51e21c39aaSAnton Nayshtut #define ST_CTIM_NSEC_SET(stbuf, val) do { } while (0) 52e21c39aaSAnton Nayshtut #define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0) 53e21c39aaSAnton Nayshtut #endif 54e21c39aaSAnton Nayshtut 55e21c39aaSAnton Nayshtut struct lo_cred { 56e21c39aaSAnton Nayshtut uid_t euid; 57e21c39aaSAnton Nayshtut gid_t egid; 58e21c39aaSAnton Nayshtut }; 59e21c39aaSAnton Nayshtut 60e21c39aaSAnton Nayshtut /** Inode number type */ 61e21c39aaSAnton Nayshtut typedef uint64_t spdk_ino_t; 62e21c39aaSAnton Nayshtut 63e21c39aaSAnton Nayshtut struct lo_key { 64e21c39aaSAnton Nayshtut ino_t ino; 65e21c39aaSAnton Nayshtut dev_t dev; 66e21c39aaSAnton Nayshtut }; 67e21c39aaSAnton Nayshtut 68e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle { 69e21c39aaSAnton Nayshtut int fd; 70e21c39aaSAnton Nayshtut struct { 71e21c39aaSAnton Nayshtut DIR *dp; 72e21c39aaSAnton Nayshtut struct dirent *entry; 73e21c39aaSAnton Nayshtut off_t offset; 74e21c39aaSAnton Nayshtut } dir; 75e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject; 76e21c39aaSAnton Nayshtut TAILQ_ENTRY(spdk_fsdev_file_handle) link; 77e21c39aaSAnton Nayshtut }; 78e21c39aaSAnton Nayshtut 79e21c39aaSAnton Nayshtut #define FOBJECT_FMT "ino=%" PRIu64 " dev=%" PRIu64 80e21c39aaSAnton Nayshtut #define FOBJECT_ARGS(fo) ((uint64_t)(fo)->key.ino), ((uint64_t)(fo)->key.dev) 81e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object { 82e21c39aaSAnton Nayshtut uint32_t is_symlink : 1; 83e21c39aaSAnton Nayshtut uint32_t is_dir : 1; 84e21c39aaSAnton Nayshtut uint32_t reserved : 30; 85e21c39aaSAnton Nayshtut int fd; 86e21c39aaSAnton Nayshtut char *fd_str; 87e21c39aaSAnton Nayshtut struct lo_key key; 88e21c39aaSAnton Nayshtut uint64_t refcount; 89e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject; 90e21c39aaSAnton Nayshtut TAILQ_ENTRY(spdk_fsdev_file_object) link; 91e21c39aaSAnton Nayshtut TAILQ_HEAD(, spdk_fsdev_file_object) leafs; 92e21c39aaSAnton Nayshtut TAILQ_HEAD(, spdk_fsdev_file_handle) handles; 93e21c39aaSAnton Nayshtut struct spdk_spinlock lock; 94e21c39aaSAnton Nayshtut char name[]; 95e21c39aaSAnton Nayshtut }; 96e21c39aaSAnton Nayshtut 97e21c39aaSAnton Nayshtut struct aio_fsdev { 98e21c39aaSAnton Nayshtut struct spdk_fsdev fsdev; 99*6cb9c75cSAnton Nayshtut struct spdk_fsdev_mount_opts mount_opts; 100e21c39aaSAnton Nayshtut char *root_path; 101e21c39aaSAnton Nayshtut int proc_self_fd; 102e21c39aaSAnton Nayshtut pthread_mutex_t mutex; 103e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *root; 104e21c39aaSAnton Nayshtut TAILQ_ENTRY(aio_fsdev) tailq; 105e21c39aaSAnton Nayshtut bool xattr_enabled; 10692108e0aSYoray Zack bool skip_rw; 107e21c39aaSAnton Nayshtut }; 108e21c39aaSAnton Nayshtut 109e21c39aaSAnton Nayshtut struct aio_fsdev_io { 110e21c39aaSAnton Nayshtut struct spdk_aio_mgr_io *aio; 111e21c39aaSAnton Nayshtut struct aio_io_channel *ch; 112e21c39aaSAnton Nayshtut TAILQ_ENTRY(aio_fsdev_io) link; 113e21c39aaSAnton Nayshtut }; 114e21c39aaSAnton Nayshtut 115e21c39aaSAnton Nayshtut struct aio_io_channel { 116e21c39aaSAnton Nayshtut struct spdk_poller *poller; 117e21c39aaSAnton Nayshtut struct spdk_aio_mgr *mgr; 118e21c39aaSAnton Nayshtut TAILQ_HEAD(, aio_fsdev_io) ios_in_progress; 11992108e0aSYoray Zack TAILQ_HEAD(, aio_fsdev_io) ios_to_complete; 120e21c39aaSAnton Nayshtut }; 121e21c39aaSAnton Nayshtut 122e21c39aaSAnton Nayshtut static TAILQ_HEAD(, aio_fsdev) g_aio_fsdev_head = TAILQ_HEAD_INITIALIZER( 123e21c39aaSAnton Nayshtut g_aio_fsdev_head); 124e21c39aaSAnton Nayshtut 125e21c39aaSAnton Nayshtut static inline struct aio_fsdev * 126e21c39aaSAnton Nayshtut fsdev_to_aio_fsdev(struct spdk_fsdev *fsdev) 127e21c39aaSAnton Nayshtut { 128e21c39aaSAnton Nayshtut return SPDK_CONTAINEROF(fsdev, struct aio_fsdev, fsdev); 129e21c39aaSAnton Nayshtut } 130e21c39aaSAnton Nayshtut 131e21c39aaSAnton Nayshtut static inline struct spdk_fsdev_io * 132e21c39aaSAnton Nayshtut aio_to_fsdev_io(const struct aio_fsdev_io *aio_io) 133e21c39aaSAnton Nayshtut { 134e21c39aaSAnton Nayshtut return SPDK_CONTAINEROF(aio_io, struct spdk_fsdev_io, driver_ctx); 135e21c39aaSAnton Nayshtut } 136e21c39aaSAnton Nayshtut 137e21c39aaSAnton Nayshtut static inline struct aio_fsdev_io * 138e21c39aaSAnton Nayshtut fsdev_to_aio_io(const struct spdk_fsdev_io *fsdev_io) 139e21c39aaSAnton Nayshtut { 140e21c39aaSAnton Nayshtut return (struct aio_fsdev_io *)fsdev_io->driver_ctx; 141e21c39aaSAnton Nayshtut } 142e21c39aaSAnton Nayshtut 143e21c39aaSAnton Nayshtut static inline bool 144e21c39aaSAnton Nayshtut fsdev_aio_is_valid_fobject(struct aio_fsdev *vfsdev, struct spdk_fsdev_file_object *fobject) 145e21c39aaSAnton Nayshtut { 146e21c39aaSAnton Nayshtut return fobject != NULL; 147e21c39aaSAnton Nayshtut } 148e21c39aaSAnton Nayshtut 149e21c39aaSAnton Nayshtut static inline bool 150e21c39aaSAnton Nayshtut fsdev_aio_is_valid_fhandle(struct aio_fsdev *vfsdev, struct spdk_fsdev_file_handle *fhandle) 151e21c39aaSAnton Nayshtut { 152e21c39aaSAnton Nayshtut return fhandle != NULL; 153e21c39aaSAnton Nayshtut } 154e21c39aaSAnton Nayshtut 155e21c39aaSAnton Nayshtut static int 156e21c39aaSAnton Nayshtut is_dot_or_dotdot(const char *name) 157e21c39aaSAnton Nayshtut { 158e21c39aaSAnton Nayshtut return name[0] == '.' && (name[1] == '\0' || 159e21c39aaSAnton Nayshtut (name[1] == '.' && name[2] == '\0')); 160e21c39aaSAnton Nayshtut } 161e21c39aaSAnton Nayshtut 162e21c39aaSAnton Nayshtut /* Is `path` a single path component that is not "." or ".."? */ 163e21c39aaSAnton Nayshtut static int 164e21c39aaSAnton Nayshtut is_safe_path_component(const char *path) 165e21c39aaSAnton Nayshtut { 166e21c39aaSAnton Nayshtut if (strchr(path, '/')) { 167e21c39aaSAnton Nayshtut return 0; 168e21c39aaSAnton Nayshtut } 169e21c39aaSAnton Nayshtut 170e21c39aaSAnton Nayshtut return !is_dot_or_dotdot(path); 171e21c39aaSAnton Nayshtut } 172e21c39aaSAnton Nayshtut 173e21c39aaSAnton Nayshtut static struct spdk_fsdev_file_object * 174e21c39aaSAnton Nayshtut lo_find_leaf_unsafe(struct spdk_fsdev_file_object *fobject, ino_t ino, dev_t dev) 175e21c39aaSAnton Nayshtut { 176e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *leaf_fobject; 177e21c39aaSAnton Nayshtut 178e21c39aaSAnton Nayshtut TAILQ_FOREACH(leaf_fobject, &fobject->leafs, link) { 179e21c39aaSAnton Nayshtut if (leaf_fobject->key.ino == ino && leaf_fobject->key.dev == dev) { 180e21c39aaSAnton Nayshtut return leaf_fobject; 181e21c39aaSAnton Nayshtut } 182e21c39aaSAnton Nayshtut } 183e21c39aaSAnton Nayshtut 184e21c39aaSAnton Nayshtut return NULL; 185e21c39aaSAnton Nayshtut } 186e21c39aaSAnton Nayshtut 187e21c39aaSAnton Nayshtut /* This function returns: 188e21c39aaSAnton Nayshtut * 1 if the refcount is still non zero 189e21c39aaSAnton Nayshtut * a negative error number if the refcount became zero, the file object was deleted but the defered underlying file deletion failed 190e21c39aaSAnton Nayshtut * 0 if the refcount became zero, the file object was deleted and eithr the underlying file deletion wasn't defered or succeeded 191e21c39aaSAnton Nayshtut */ 192e21c39aaSAnton Nayshtut static int 193e21c39aaSAnton Nayshtut file_object_unref(struct spdk_fsdev_file_object *fobject, uint32_t count) 194e21c39aaSAnton Nayshtut { 195e21c39aaSAnton Nayshtut int res = 0; 196e21c39aaSAnton Nayshtut 197e21c39aaSAnton Nayshtut spdk_spin_lock(&fobject->lock); 198e21c39aaSAnton Nayshtut assert(fobject->refcount >= count); 199e21c39aaSAnton Nayshtut fobject->refcount -= count; 200e21c39aaSAnton Nayshtut spdk_spin_unlock(&fobject->lock); 201e21c39aaSAnton Nayshtut 202e21c39aaSAnton Nayshtut if (!fobject->refcount) { 203e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject = fobject->parent_fobject; 204e21c39aaSAnton Nayshtut 205e21c39aaSAnton Nayshtut if (parent_fobject) { 206e21c39aaSAnton Nayshtut spdk_spin_lock(&parent_fobject->lock); 207e21c39aaSAnton Nayshtut TAILQ_REMOVE(&parent_fobject->leafs, fobject, link); 208e21c39aaSAnton Nayshtut spdk_spin_unlock(&parent_fobject->lock); 209e21c39aaSAnton Nayshtut file_object_unref(parent_fobject, 1); /* unref by the leaf */ 210e21c39aaSAnton Nayshtut } 211e21c39aaSAnton Nayshtut 212e21c39aaSAnton Nayshtut spdk_spin_destroy(&fobject->lock); 213e21c39aaSAnton Nayshtut close(fobject->fd); 214e21c39aaSAnton Nayshtut free(fobject->fd_str); 215e21c39aaSAnton Nayshtut free(fobject); 216e21c39aaSAnton Nayshtut } 217e21c39aaSAnton Nayshtut 218e21c39aaSAnton Nayshtut return res; 219e21c39aaSAnton Nayshtut } 220e21c39aaSAnton Nayshtut 221e21c39aaSAnton Nayshtut static void 222e21c39aaSAnton Nayshtut file_object_ref(struct spdk_fsdev_file_object *fobject) 223e21c39aaSAnton Nayshtut { 224e21c39aaSAnton Nayshtut spdk_spin_lock(&fobject->lock); 225e21c39aaSAnton Nayshtut fobject->refcount++; 226e21c39aaSAnton Nayshtut spdk_spin_unlock(&fobject->lock); 227e21c39aaSAnton Nayshtut } 228e21c39aaSAnton Nayshtut 229e21c39aaSAnton Nayshtut static struct spdk_fsdev_file_object * 230e21c39aaSAnton Nayshtut file_object_create_unsafe(struct spdk_fsdev_file_object *parent_fobject, int fd, ino_t ino, 231e21c39aaSAnton Nayshtut dev_t dev, mode_t mode) 232e21c39aaSAnton Nayshtut { 233e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject; 234e21c39aaSAnton Nayshtut 235e21c39aaSAnton Nayshtut fobject = calloc(1, sizeof(*fobject)); 236e21c39aaSAnton Nayshtut if (!fobject) { 237e21c39aaSAnton Nayshtut SPDK_ERRLOG("Cannot alloc fobject\n"); 238e21c39aaSAnton Nayshtut return NULL; 239e21c39aaSAnton Nayshtut } 240e21c39aaSAnton Nayshtut 241e21c39aaSAnton Nayshtut fobject->fd_str = spdk_sprintf_alloc("%d", fd); 242e21c39aaSAnton Nayshtut if (!fobject->fd_str) { 243e21c39aaSAnton Nayshtut SPDK_ERRLOG("Cannot alloc fd_str\n"); 244e21c39aaSAnton Nayshtut free(fobject); 245e21c39aaSAnton Nayshtut return NULL; 246e21c39aaSAnton Nayshtut } 247e21c39aaSAnton Nayshtut 248e21c39aaSAnton Nayshtut fobject->fd = fd; 249e21c39aaSAnton Nayshtut fobject->key.ino = ino; 250e21c39aaSAnton Nayshtut fobject->key.dev = dev; 251e21c39aaSAnton Nayshtut fobject->refcount = 1; 252e21c39aaSAnton Nayshtut fobject->is_symlink = S_ISLNK(mode) ? 1 : 0; 253e21c39aaSAnton Nayshtut fobject->is_dir = S_ISDIR(mode) ? 1 : 0; 254e21c39aaSAnton Nayshtut 255e21c39aaSAnton Nayshtut TAILQ_INIT(&fobject->handles); 256e21c39aaSAnton Nayshtut TAILQ_INIT(&fobject->leafs); 257e21c39aaSAnton Nayshtut spdk_spin_init(&fobject->lock); 258e21c39aaSAnton Nayshtut 259e21c39aaSAnton Nayshtut if (parent_fobject) { 260e21c39aaSAnton Nayshtut fobject->parent_fobject = parent_fobject; 261e21c39aaSAnton Nayshtut TAILQ_INSERT_TAIL(&parent_fobject->leafs, fobject, link); 262e21c39aaSAnton Nayshtut parent_fobject->refcount++; 263e21c39aaSAnton Nayshtut } 264e21c39aaSAnton Nayshtut 265e21c39aaSAnton Nayshtut return fobject; 266e21c39aaSAnton Nayshtut } 267e21c39aaSAnton Nayshtut 268e21c39aaSAnton Nayshtut static struct spdk_fsdev_file_handle * 269e21c39aaSAnton Nayshtut file_handle_create(struct spdk_fsdev_file_object *fobject, int fd) 270e21c39aaSAnton Nayshtut { 271e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle; 272e21c39aaSAnton Nayshtut 273e21c39aaSAnton Nayshtut fhandle = calloc(1, sizeof(*fhandle)); 274e21c39aaSAnton Nayshtut if (!fhandle) { 275e21c39aaSAnton Nayshtut SPDK_ERRLOG("Cannot alloc fhandle\n"); 276e21c39aaSAnton Nayshtut return NULL; 277e21c39aaSAnton Nayshtut } 278e21c39aaSAnton Nayshtut 279e21c39aaSAnton Nayshtut fhandle->fobject = fobject; 280e21c39aaSAnton Nayshtut fhandle->fd = fd; 281e21c39aaSAnton Nayshtut 282e21c39aaSAnton Nayshtut spdk_spin_lock(&fobject->lock); 283e21c39aaSAnton Nayshtut fobject->refcount++; 284e21c39aaSAnton Nayshtut TAILQ_INSERT_TAIL(&fobject->handles, fhandle, link); 285e21c39aaSAnton Nayshtut spdk_spin_unlock(&fobject->lock); 286e21c39aaSAnton Nayshtut 287e21c39aaSAnton Nayshtut return fhandle; 288e21c39aaSAnton Nayshtut } 289e21c39aaSAnton Nayshtut 290e21c39aaSAnton Nayshtut static void 291e21c39aaSAnton Nayshtut file_handle_delete(struct spdk_fsdev_file_handle *fhandle) 292e21c39aaSAnton Nayshtut { 293e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fhandle->fobject; 294e21c39aaSAnton Nayshtut 295e21c39aaSAnton Nayshtut spdk_spin_lock(&fobject->lock); 296e21c39aaSAnton Nayshtut fobject->refcount--; 297e21c39aaSAnton Nayshtut TAILQ_REMOVE(&fobject->handles, fhandle, link); 298e21c39aaSAnton Nayshtut spdk_spin_unlock(&fobject->lock); 299e21c39aaSAnton Nayshtut 300e21c39aaSAnton Nayshtut if (fhandle->dir.dp) { 301e21c39aaSAnton Nayshtut closedir(fhandle->dir.dp); 302e21c39aaSAnton Nayshtut } 303e21c39aaSAnton Nayshtut 304e21c39aaSAnton Nayshtut close(fhandle->fd); 305e21c39aaSAnton Nayshtut free(fhandle); 306e21c39aaSAnton Nayshtut } 307e21c39aaSAnton Nayshtut 308e21c39aaSAnton Nayshtut static int 309e21c39aaSAnton Nayshtut file_object_fill_attr(struct spdk_fsdev_file_object *fobject, struct spdk_fsdev_file_attr *attr) 310e21c39aaSAnton Nayshtut { 311e21c39aaSAnton Nayshtut struct stat stbuf; 312e21c39aaSAnton Nayshtut int res; 313e21c39aaSAnton Nayshtut 314e21c39aaSAnton Nayshtut res = fstatat(fobject->fd, "", &stbuf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); 315e21c39aaSAnton Nayshtut if (res == -1) { 316e21c39aaSAnton Nayshtut res = -errno; 317e21c39aaSAnton Nayshtut SPDK_ERRLOG("fstatat() failed with %d\n", res); 318e21c39aaSAnton Nayshtut return res; 319e21c39aaSAnton Nayshtut } 320e21c39aaSAnton Nayshtut 321e21c39aaSAnton Nayshtut memset(attr, 0, sizeof(*attr)); 322e21c39aaSAnton Nayshtut 323e21c39aaSAnton Nayshtut attr->ino = stbuf.st_ino; 324e21c39aaSAnton Nayshtut attr->size = stbuf.st_size; 325e21c39aaSAnton Nayshtut attr->blocks = stbuf.st_blocks; 326e21c39aaSAnton Nayshtut attr->atime = stbuf.st_atime; 327e21c39aaSAnton Nayshtut attr->mtime = stbuf.st_mtime; 328e21c39aaSAnton Nayshtut attr->ctime = stbuf.st_ctime; 329e21c39aaSAnton Nayshtut attr->atimensec = ST_ATIM_NSEC(&stbuf); 330e21c39aaSAnton Nayshtut attr->mtimensec = ST_MTIM_NSEC(&stbuf); 331e21c39aaSAnton Nayshtut attr->ctimensec = ST_CTIM_NSEC(&stbuf); 332e21c39aaSAnton Nayshtut attr->mode = stbuf.st_mode; 333e21c39aaSAnton Nayshtut attr->nlink = stbuf.st_nlink; 334e21c39aaSAnton Nayshtut attr->uid = stbuf.st_uid; 335e21c39aaSAnton Nayshtut attr->gid = stbuf.st_gid; 336e21c39aaSAnton Nayshtut attr->rdev = stbuf.st_rdev; 337e21c39aaSAnton Nayshtut attr->blksize = stbuf.st_blksize; 338e21c39aaSAnton Nayshtut attr->valid_ms = DEFAULT_TIMEOUT_MS; 339e21c39aaSAnton Nayshtut 340e21c39aaSAnton Nayshtut return 0; 341e21c39aaSAnton Nayshtut } 342e21c39aaSAnton Nayshtut 343e21c39aaSAnton Nayshtut static int 344e21c39aaSAnton Nayshtut utimensat_empty(struct aio_fsdev *vfsdev, struct spdk_fsdev_file_object *fobject, 345e21c39aaSAnton Nayshtut const struct timespec *tv) 346e21c39aaSAnton Nayshtut { 347e21c39aaSAnton Nayshtut int res; 348e21c39aaSAnton Nayshtut 349e21c39aaSAnton Nayshtut if (fobject->is_symlink) { 350e21c39aaSAnton Nayshtut res = utimensat(fobject->fd, "", tv, AT_EMPTY_PATH); 351e21c39aaSAnton Nayshtut if (res == -1 && errno == EINVAL) { 352e21c39aaSAnton Nayshtut /* Sorry, no race free way to set times on symlink. */ 353e21c39aaSAnton Nayshtut errno = EPERM; 354e21c39aaSAnton Nayshtut } 355e21c39aaSAnton Nayshtut } else { 356e21c39aaSAnton Nayshtut res = utimensat(vfsdev->proc_self_fd, fobject->fd_str, tv, 0); 357e21c39aaSAnton Nayshtut } 358e21c39aaSAnton Nayshtut 359e21c39aaSAnton Nayshtut return res; 360e21c39aaSAnton Nayshtut } 361e21c39aaSAnton Nayshtut 362cc5f4049SAnton Nayshtut static void 363*6cb9c75cSAnton Nayshtut fsdev_free_leafs(struct spdk_fsdev_file_object *fobject, bool unref_fobject) 364cc5f4049SAnton Nayshtut { 365cc5f4049SAnton Nayshtut while (!TAILQ_EMPTY(&fobject->handles)) { 366cc5f4049SAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = TAILQ_FIRST(&fobject->handles); 367cc5f4049SAnton Nayshtut file_handle_delete(fhandle); 368cc5f4049SAnton Nayshtut #ifdef __clang_analyzer__ 369cc5f4049SAnton Nayshtut /* 370cc5f4049SAnton Nayshtut * scan-build fails to comprehend that file_handle_delete() removes the fhandle 371cc5f4049SAnton Nayshtut * from the queue, so it thinks it's remained accessible and throws the "Use of 372cc5f4049SAnton Nayshtut * memory after it is freed" error here. 373cc5f4049SAnton Nayshtut * The loop below "teaches" the scan-build that the freed fhandle is not on the 374cc5f4049SAnton Nayshtut * list anymore and supresses the error in this way. 375cc5f4049SAnton Nayshtut */ 376cc5f4049SAnton Nayshtut struct spdk_fsdev_file_handle *tmp; 377cc5f4049SAnton Nayshtut TAILQ_FOREACH(tmp, &fobject->handles, link) { 378cc5f4049SAnton Nayshtut assert(tmp != fhandle); 379cc5f4049SAnton Nayshtut } 380cc5f4049SAnton Nayshtut #endif 381cc5f4049SAnton Nayshtut } 382cc5f4049SAnton Nayshtut 383cc5f4049SAnton Nayshtut while (!TAILQ_EMPTY(&fobject->leafs)) { 384cc5f4049SAnton Nayshtut struct spdk_fsdev_file_object *leaf_fobject = TAILQ_FIRST(&fobject->leafs); 385*6cb9c75cSAnton Nayshtut fsdev_free_leafs(leaf_fobject, true); 386cc5f4049SAnton Nayshtut } 387cc5f4049SAnton Nayshtut 388*6cb9c75cSAnton Nayshtut if (fobject->refcount && unref_fobject) { 389cc5f4049SAnton Nayshtut /* if still referenced - zero refcount */ 390cc5f4049SAnton Nayshtut int res = file_object_unref(fobject, fobject->refcount); 391cc5f4049SAnton Nayshtut assert(res == 0); 392cc5f4049SAnton Nayshtut UNUSED(res); 393cc5f4049SAnton Nayshtut } 394cc5f4049SAnton Nayshtut } 395cc5f4049SAnton Nayshtut 396e21c39aaSAnton Nayshtut static int 397e21c39aaSAnton Nayshtut lo_getattr(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 398e21c39aaSAnton Nayshtut { 399e21c39aaSAnton Nayshtut int res; 400e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 401e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.getattr.fobject; 402e21c39aaSAnton Nayshtut 403e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 404e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 405e21c39aaSAnton Nayshtut return -EINVAL; 406e21c39aaSAnton Nayshtut } 407e21c39aaSAnton Nayshtut 408e21c39aaSAnton Nayshtut res = file_object_fill_attr(fobject, &fsdev_io->u_out.getattr.attr); 409e21c39aaSAnton Nayshtut if (res) { 410e21c39aaSAnton Nayshtut SPDK_ERRLOG("Cannot fill attr for " FOBJECT_FMT " (err=%d)\n", FOBJECT_ARGS(fobject), res); 411e21c39aaSAnton Nayshtut return res; 412e21c39aaSAnton Nayshtut } 413e21c39aaSAnton Nayshtut 414e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "GETATTR succeeded for " FOBJECT_FMT "\n", FOBJECT_ARGS(fobject)); 415e21c39aaSAnton Nayshtut return 0; 416e21c39aaSAnton Nayshtut } 417e21c39aaSAnton Nayshtut 418e21c39aaSAnton Nayshtut static int 419e21c39aaSAnton Nayshtut lo_opendir(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 420e21c39aaSAnton Nayshtut { 421e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 422e21c39aaSAnton Nayshtut int error; 423e21c39aaSAnton Nayshtut int fd; 424e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.opendir.fobject; 425e21c39aaSAnton Nayshtut uint32_t flags = fsdev_io->u_in.opendir.flags; 426e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = NULL; 427e21c39aaSAnton Nayshtut 428e21c39aaSAnton Nayshtut UNUSED(flags); 429e21c39aaSAnton Nayshtut 430e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 431e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 432e21c39aaSAnton Nayshtut return -EINVAL; 433e21c39aaSAnton Nayshtut } 434e21c39aaSAnton Nayshtut 435e21c39aaSAnton Nayshtut fd = openat(fobject->fd, ".", O_RDONLY); 436e21c39aaSAnton Nayshtut if (fd == -1) { 437e21c39aaSAnton Nayshtut error = -errno; 438e21c39aaSAnton Nayshtut SPDK_ERRLOG("openat failed for " FOBJECT_FMT " (err=%d)\n", FOBJECT_ARGS(fobject), error); 439e21c39aaSAnton Nayshtut goto out_err; 440e21c39aaSAnton Nayshtut } 441e21c39aaSAnton Nayshtut 442e21c39aaSAnton Nayshtut fhandle = file_handle_create(fobject, fd); 44339dafea4SMarcin Spiewak if (fhandle == NULL) { 444e21c39aaSAnton Nayshtut error = -ENOMEM; 445e21c39aaSAnton Nayshtut SPDK_ERRLOG("file_handle_create failed for " FOBJECT_FMT " (err=%d)\n", FOBJECT_ARGS(fobject), 446e21c39aaSAnton Nayshtut error); 447e21c39aaSAnton Nayshtut goto out_err; 448e21c39aaSAnton Nayshtut } 449e21c39aaSAnton Nayshtut 450e21c39aaSAnton Nayshtut fhandle->dir.dp = fdopendir(fd); 451e21c39aaSAnton Nayshtut if (fhandle->dir.dp == NULL) { 452e21c39aaSAnton Nayshtut error = -errno; 453e21c39aaSAnton Nayshtut SPDK_ERRLOG("fdopendir failed for " FOBJECT_FMT " (err=%d)\n", FOBJECT_ARGS(fobject), error); 454e21c39aaSAnton Nayshtut goto out_err; 455e21c39aaSAnton Nayshtut } 456e21c39aaSAnton Nayshtut 457e21c39aaSAnton Nayshtut fhandle->dir.offset = 0; 458e21c39aaSAnton Nayshtut fhandle->dir.entry = NULL; 459e21c39aaSAnton Nayshtut 460e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "OPENDIR succeeded for " FOBJECT_FMT " (fh=%p)\n", 461e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), fhandle); 462e21c39aaSAnton Nayshtut 463e21c39aaSAnton Nayshtut fsdev_io->u_out.opendir.fhandle = fhandle; 464e21c39aaSAnton Nayshtut 465e21c39aaSAnton Nayshtut return 0; 466e21c39aaSAnton Nayshtut 467e21c39aaSAnton Nayshtut out_err: 468e21c39aaSAnton Nayshtut if (fhandle) { 469e21c39aaSAnton Nayshtut file_handle_delete(fhandle); 470e21c39aaSAnton Nayshtut } else if (fd != -1) { 471e21c39aaSAnton Nayshtut close(fd); 472e21c39aaSAnton Nayshtut } 473e21c39aaSAnton Nayshtut 474e21c39aaSAnton Nayshtut return error; 475e21c39aaSAnton Nayshtut } 476e21c39aaSAnton Nayshtut 477e21c39aaSAnton Nayshtut static int 478e21c39aaSAnton Nayshtut lo_releasedir(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 479e21c39aaSAnton Nayshtut { 480e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 481e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.releasedir.fobject; 482e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.releasedir.fhandle; 483e21c39aaSAnton Nayshtut 484e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 485e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 486e21c39aaSAnton Nayshtut return -EINVAL; 487e21c39aaSAnton Nayshtut } 488e21c39aaSAnton Nayshtut 489e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle)) { 490e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle: %p\n", fhandle); 491e21c39aaSAnton Nayshtut return -EINVAL; 492e21c39aaSAnton Nayshtut } 493e21c39aaSAnton Nayshtut 494e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "RELEASEDIR succeeded for " FOBJECT_FMT " (fh=%p)\n", 495e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), fhandle); 49656e509c8SMarcin Spiewak 49756e509c8SMarcin Spiewak file_handle_delete(fhandle); 498e21c39aaSAnton Nayshtut 499e21c39aaSAnton Nayshtut return 0; 500e21c39aaSAnton Nayshtut } 501e21c39aaSAnton Nayshtut 502e21c39aaSAnton Nayshtut static int 503*6cb9c75cSAnton Nayshtut lo_set_mount_opts(struct aio_fsdev *vfsdev, struct spdk_fsdev_mount_opts *opts) 504d00039dbSAnton Nayshtut { 505*6cb9c75cSAnton Nayshtut assert(opts != NULL); 506d00039dbSAnton Nayshtut assert(opts->opts_size != 0); 507d00039dbSAnton Nayshtut 508d00039dbSAnton Nayshtut UNUSED(vfsdev); 509d00039dbSAnton Nayshtut 510*6cb9c75cSAnton Nayshtut if (opts->opts_size > offsetof(struct spdk_fsdev_mount_opts, max_write)) { 511d00039dbSAnton Nayshtut /* Set the value the aio fsdev was created with */ 512*6cb9c75cSAnton Nayshtut opts->max_write = vfsdev->mount_opts.max_write; 513d00039dbSAnton Nayshtut } 514d00039dbSAnton Nayshtut 515*6cb9c75cSAnton Nayshtut if (opts->opts_size > offsetof(struct spdk_fsdev_mount_opts, writeback_cache_enabled)) { 516*6cb9c75cSAnton Nayshtut if (vfsdev->mount_opts.writeback_cache_enabled) { 517d00039dbSAnton Nayshtut /* The writeback_cache_enabled was enabled upon creation => we follow the opts */ 518*6cb9c75cSAnton Nayshtut vfsdev->mount_opts.writeback_cache_enabled = opts->writeback_cache_enabled; 519d00039dbSAnton Nayshtut } else { 520d00039dbSAnton Nayshtut /* The writeback_cache_enabled was disabled upon creation => we reflect it in the opts */ 521d00039dbSAnton Nayshtut opts->writeback_cache_enabled = false; 522d00039dbSAnton Nayshtut } 523d00039dbSAnton Nayshtut } 524d00039dbSAnton Nayshtut 525d00039dbSAnton Nayshtut /* The AIO doesn't apply any additional restrictions, so we just accept the requested opts */ 526d00039dbSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, 527d00039dbSAnton Nayshtut "aio filesystem %s: opts updated: max_write=%" PRIu32 ", writeback_cache=%" PRIu8 "\n", 528*6cb9c75cSAnton Nayshtut vfsdev->fsdev.name, vfsdev->mount_opts.max_write, vfsdev->mount_opts.writeback_cache_enabled); 529*6cb9c75cSAnton Nayshtut 530*6cb9c75cSAnton Nayshtut return 0; 531*6cb9c75cSAnton Nayshtut } 532*6cb9c75cSAnton Nayshtut 533*6cb9c75cSAnton Nayshtut static int 534*6cb9c75cSAnton Nayshtut lo_mount(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 535*6cb9c75cSAnton Nayshtut { 536*6cb9c75cSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 537*6cb9c75cSAnton Nayshtut struct spdk_fsdev_mount_opts *in_opts = &fsdev_io->u_in.mount.opts; 538*6cb9c75cSAnton Nayshtut 539*6cb9c75cSAnton Nayshtut fsdev_io->u_out.mount.opts = *in_opts; 540*6cb9c75cSAnton Nayshtut lo_set_mount_opts(vfsdev, &fsdev_io->u_out.mount.opts); 541*6cb9c75cSAnton Nayshtut file_object_ref(vfsdev->root); 542*6cb9c75cSAnton Nayshtut fsdev_io->u_out.mount.root_fobject = vfsdev->root; 543*6cb9c75cSAnton Nayshtut 544*6cb9c75cSAnton Nayshtut return 0; 545*6cb9c75cSAnton Nayshtut } 546*6cb9c75cSAnton Nayshtut 547*6cb9c75cSAnton Nayshtut static int 548*6cb9c75cSAnton Nayshtut lo_umount(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 549*6cb9c75cSAnton Nayshtut { 550*6cb9c75cSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 551*6cb9c75cSAnton Nayshtut 552*6cb9c75cSAnton Nayshtut fsdev_free_leafs(vfsdev->root, false); 553*6cb9c75cSAnton Nayshtut file_object_unref(vfsdev->root, 1); /* reference by mount */ 554d00039dbSAnton Nayshtut 555d00039dbSAnton Nayshtut return 0; 556d00039dbSAnton Nayshtut } 557d00039dbSAnton Nayshtut 558d00039dbSAnton Nayshtut static int 559e21c39aaSAnton Nayshtut lo_do_lookup(struct aio_fsdev *vfsdev, struct spdk_fsdev_file_object *parent_fobject, 560e21c39aaSAnton Nayshtut const char *name, struct spdk_fsdev_file_object **pfobject, 561e21c39aaSAnton Nayshtut struct spdk_fsdev_file_attr *attr) 562e21c39aaSAnton Nayshtut { 563e21c39aaSAnton Nayshtut int newfd; 564e21c39aaSAnton Nayshtut int res; 565e21c39aaSAnton Nayshtut struct stat stat; 566e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject; 567e21c39aaSAnton Nayshtut 568e21c39aaSAnton Nayshtut /* Do not allow escaping root directory */ 569e21c39aaSAnton Nayshtut if (parent_fobject == vfsdev->root && strcmp(name, "..") == 0) { 570e21c39aaSAnton Nayshtut name = "."; 571e21c39aaSAnton Nayshtut } 572e21c39aaSAnton Nayshtut 573e21c39aaSAnton Nayshtut newfd = openat(parent_fobject->fd, name, O_PATH | O_NOFOLLOW); 574e21c39aaSAnton Nayshtut if (newfd == -1) { 575e21c39aaSAnton Nayshtut res = -errno; 576e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "openat( " FOBJECT_FMT " %s) failed with %d\n", 577e21c39aaSAnton Nayshtut FOBJECT_ARGS(parent_fobject), name, res); 578e21c39aaSAnton Nayshtut return res; 579e21c39aaSAnton Nayshtut } 580e21c39aaSAnton Nayshtut 581e21c39aaSAnton Nayshtut res = fstatat(newfd, "", &stat, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); 582e21c39aaSAnton Nayshtut if (res == -1) { 583e21c39aaSAnton Nayshtut res = -errno; 584e21c39aaSAnton Nayshtut SPDK_ERRLOG("fstatat(%s) failed with %d\n", name, res); 585e21c39aaSAnton Nayshtut close(newfd); 586e21c39aaSAnton Nayshtut return res; 587e21c39aaSAnton Nayshtut } 588e21c39aaSAnton Nayshtut 589e21c39aaSAnton Nayshtut spdk_spin_lock(&parent_fobject->lock); 590e21c39aaSAnton Nayshtut fobject = lo_find_leaf_unsafe(parent_fobject, stat.st_ino, stat.st_dev); 591e21c39aaSAnton Nayshtut if (fobject) { 592e21c39aaSAnton Nayshtut close(newfd); 59339dafea4SMarcin Spiewak newfd = -1; 594e21c39aaSAnton Nayshtut file_object_ref(fobject); /* reference by a lo_do_lookup caller */ 595e21c39aaSAnton Nayshtut } else { 596e21c39aaSAnton Nayshtut fobject = file_object_create_unsafe(parent_fobject, newfd, stat.st_ino, stat.st_dev, stat.st_mode); 597e21c39aaSAnton Nayshtut } 598e21c39aaSAnton Nayshtut spdk_spin_unlock(&parent_fobject->lock); 599e21c39aaSAnton Nayshtut 600e21c39aaSAnton Nayshtut if (!fobject) { 601e21c39aaSAnton Nayshtut SPDK_ERRLOG("Cannot create file object\n"); 602e21c39aaSAnton Nayshtut close(newfd); 603e21c39aaSAnton Nayshtut return -ENOMEM; 604e21c39aaSAnton Nayshtut } 605e21c39aaSAnton Nayshtut 606e21c39aaSAnton Nayshtut if (attr) { 607e21c39aaSAnton Nayshtut res = file_object_fill_attr(fobject, attr); 608e21c39aaSAnton Nayshtut if (res) { 609e21c39aaSAnton Nayshtut SPDK_ERRLOG("fill_attr(%s) failed with %d\n", name, res); 610e21c39aaSAnton Nayshtut file_object_unref(fobject, 1); 61139dafea4SMarcin Spiewak if (newfd != -1) { 612e21c39aaSAnton Nayshtut close(newfd); 61339dafea4SMarcin Spiewak } 614e21c39aaSAnton Nayshtut return res; 615e21c39aaSAnton Nayshtut } 616e21c39aaSAnton Nayshtut } 617e21c39aaSAnton Nayshtut 618e21c39aaSAnton Nayshtut *pfobject = fobject; 619e21c39aaSAnton Nayshtut 620e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "lookup(%s) in dir " FOBJECT_FMT ": " FOBJECT_FMT " fd=%d\n", 621e21c39aaSAnton Nayshtut name, FOBJECT_ARGS(parent_fobject), FOBJECT_ARGS(fobject), fobject->fd); 622e21c39aaSAnton Nayshtut return 0; 623e21c39aaSAnton Nayshtut } 624e21c39aaSAnton Nayshtut 625e21c39aaSAnton Nayshtut static int 626e21c39aaSAnton Nayshtut lo_lookup(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 627e21c39aaSAnton Nayshtut { 628e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 629e21c39aaSAnton Nayshtut int err; 630e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject = fsdev_io->u_in.lookup.parent_fobject; 631e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.lookup.name; 632e21c39aaSAnton Nayshtut 633e21c39aaSAnton Nayshtut if (!parent_fobject) { 634e21c39aaSAnton Nayshtut err = file_object_fill_attr(vfsdev->root, &fsdev_io->u_out.lookup.attr); 635e21c39aaSAnton Nayshtut if (err) { 636e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "file_object_fill_attr(root) failed with err=%d\n", err); 637e21c39aaSAnton Nayshtut return err; 638e21c39aaSAnton Nayshtut } 639e21c39aaSAnton Nayshtut 640e21c39aaSAnton Nayshtut file_object_ref(vfsdev->root); 641e21c39aaSAnton Nayshtut fsdev_io->u_out.lookup.fobject = vfsdev->root; 642e21c39aaSAnton Nayshtut return 0; 643e21c39aaSAnton Nayshtut } 644e21c39aaSAnton Nayshtut 645e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, " name %s\n", name); 646e21c39aaSAnton Nayshtut 647e21c39aaSAnton Nayshtut /* Don't use is_safe_path_component(), allow "." and ".." for NFS export 648e21c39aaSAnton Nayshtut * support. 649e21c39aaSAnton Nayshtut */ 650e21c39aaSAnton Nayshtut if (strchr(name, '/')) { 651e21c39aaSAnton Nayshtut return -EINVAL; 652e21c39aaSAnton Nayshtut } 653e21c39aaSAnton Nayshtut 654e21c39aaSAnton Nayshtut err = lo_do_lookup(vfsdev, parent_fobject, name, &fsdev_io->u_out.lookup.fobject, 655e21c39aaSAnton Nayshtut &fsdev_io->u_out.lookup.attr); 656e21c39aaSAnton Nayshtut if (err) { 657e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "lo_do_lookup(%s) failed with err=%d\n", name, err); 658e21c39aaSAnton Nayshtut return err; 659e21c39aaSAnton Nayshtut } 660e21c39aaSAnton Nayshtut 661e21c39aaSAnton Nayshtut return 0; 662e21c39aaSAnton Nayshtut } 663e21c39aaSAnton Nayshtut 664e21c39aaSAnton Nayshtut /* 665e21c39aaSAnton Nayshtut * Change to uid/gid of caller so that file is created with ownership of caller. 666e21c39aaSAnton Nayshtut */ 667e21c39aaSAnton Nayshtut static int 668e21c39aaSAnton Nayshtut lo_change_cred(const struct lo_cred *new, struct lo_cred *old) 669e21c39aaSAnton Nayshtut { 670e21c39aaSAnton Nayshtut int res; 671e21c39aaSAnton Nayshtut 672e21c39aaSAnton Nayshtut old->euid = geteuid(); 673e21c39aaSAnton Nayshtut old->egid = getegid(); 674e21c39aaSAnton Nayshtut 675e21c39aaSAnton Nayshtut res = syscall(SYS_setresgid, -1, new->egid, -1); 676e21c39aaSAnton Nayshtut if (res == -1) { 677e21c39aaSAnton Nayshtut return -errno; 678e21c39aaSAnton Nayshtut } 679e21c39aaSAnton Nayshtut 680e21c39aaSAnton Nayshtut res = syscall(SYS_setresuid, -1, new->euid, -1); 681e21c39aaSAnton Nayshtut if (res == -1) { 682e21c39aaSAnton Nayshtut int errno_save = -errno; 683e21c39aaSAnton Nayshtut 684e21c39aaSAnton Nayshtut syscall(SYS_setresgid, -1, old->egid, -1); 685e21c39aaSAnton Nayshtut return errno_save; 686e21c39aaSAnton Nayshtut } 687e21c39aaSAnton Nayshtut 688e21c39aaSAnton Nayshtut return 0; 689e21c39aaSAnton Nayshtut } 690e21c39aaSAnton Nayshtut 691e21c39aaSAnton Nayshtut /* Regain Privileges */ 692e21c39aaSAnton Nayshtut static void 693e21c39aaSAnton Nayshtut lo_restore_cred(struct lo_cred *old) 694e21c39aaSAnton Nayshtut { 695e21c39aaSAnton Nayshtut int res; 696e21c39aaSAnton Nayshtut 697e21c39aaSAnton Nayshtut res = syscall(SYS_setresuid, -1, old->euid, -1); 698e21c39aaSAnton Nayshtut if (res == -1) { 699e21c39aaSAnton Nayshtut SPDK_ERRLOG("seteuid(%u)", old->euid); 700e21c39aaSAnton Nayshtut } 701e21c39aaSAnton Nayshtut 702e21c39aaSAnton Nayshtut res = syscall(SYS_setresgid, -1, old->egid, -1); 703e21c39aaSAnton Nayshtut if (res == -1) { 704e21c39aaSAnton Nayshtut SPDK_ERRLOG("setegid(%u)", old->egid); 705e21c39aaSAnton Nayshtut } 706e21c39aaSAnton Nayshtut } 707e21c39aaSAnton Nayshtut 708e21c39aaSAnton Nayshtut static int 709e21c39aaSAnton Nayshtut lo_readdir(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 710e21c39aaSAnton Nayshtut { 711e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 712e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.readdir.fobject; 713e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.readdir.fhandle; 714e21c39aaSAnton Nayshtut uint64_t offset = fsdev_io->u_in.readdir.offset; 715e21c39aaSAnton Nayshtut 716e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 717e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 718e21c39aaSAnton Nayshtut return -EINVAL; 719e21c39aaSAnton Nayshtut } 720e21c39aaSAnton Nayshtut 721e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle)) { 722e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle: %p\n", fhandle); 723e21c39aaSAnton Nayshtut return -EINVAL; 724e21c39aaSAnton Nayshtut } 725e21c39aaSAnton Nayshtut 726e21c39aaSAnton Nayshtut if (((off_t)offset) != fhandle->dir.offset) { 727e21c39aaSAnton Nayshtut seekdir(fhandle->dir.dp, offset); 728e21c39aaSAnton Nayshtut fhandle->dir.entry = NULL; 729e21c39aaSAnton Nayshtut fhandle->dir.offset = offset; 730e21c39aaSAnton Nayshtut } 731e21c39aaSAnton Nayshtut 732e21c39aaSAnton Nayshtut while (1) { 733e21c39aaSAnton Nayshtut off_t nextoff; 734e21c39aaSAnton Nayshtut const char *name; 735e21c39aaSAnton Nayshtut int res; 736e21c39aaSAnton Nayshtut 737e21c39aaSAnton Nayshtut if (!fhandle->dir.entry) { 738e21c39aaSAnton Nayshtut errno = 0; 739e21c39aaSAnton Nayshtut fhandle->dir.entry = readdir(fhandle->dir.dp); 740e21c39aaSAnton Nayshtut if (!fhandle->dir.entry) { 741e21c39aaSAnton Nayshtut if (errno) { /* Error */ 742e21c39aaSAnton Nayshtut res = -errno; 743e21c39aaSAnton Nayshtut SPDK_ERRLOG("readdir failed with err=%d", res); 744e21c39aaSAnton Nayshtut return res; 745e21c39aaSAnton Nayshtut } else { /* End of stream */ 746e21c39aaSAnton Nayshtut break; 747e21c39aaSAnton Nayshtut } 748e21c39aaSAnton Nayshtut } 749e21c39aaSAnton Nayshtut } 750e21c39aaSAnton Nayshtut 751e21c39aaSAnton Nayshtut nextoff = fhandle->dir.entry->d_off; 752e21c39aaSAnton Nayshtut name = fhandle->dir.entry->d_name; 753e21c39aaSAnton Nayshtut 754e21c39aaSAnton Nayshtut /* Hide root's parent directory */ 755e21c39aaSAnton Nayshtut if (fobject == vfsdev->root && strcmp(name, "..") == 0) { 756e21c39aaSAnton Nayshtut goto skip_entry; 757e21c39aaSAnton Nayshtut } 758e21c39aaSAnton Nayshtut 759e21c39aaSAnton Nayshtut if (is_dot_or_dotdot(name)) { 760e21c39aaSAnton Nayshtut fsdev_io->u_out.readdir.fobject = NULL; 761e21c39aaSAnton Nayshtut memset(&fsdev_io->u_out.readdir.attr, 0, sizeof(fsdev_io->u_out.readdir.attr)); 762e21c39aaSAnton Nayshtut fsdev_io->u_out.readdir.attr.ino = fhandle->dir.entry->d_ino; 763e21c39aaSAnton Nayshtut fsdev_io->u_out.readdir.attr.mode = DT_DIR << 12; 764e21c39aaSAnton Nayshtut goto skip_lookup; 765e21c39aaSAnton Nayshtut } 766e21c39aaSAnton Nayshtut 767e21c39aaSAnton Nayshtut res = lo_do_lookup(vfsdev, fobject, name, &fsdev_io->u_out.readdir.fobject, 768e21c39aaSAnton Nayshtut &fsdev_io->u_out.readdir.attr); 769e21c39aaSAnton Nayshtut if (res) { 770e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "lo_do_lookup(%s) failed with err=%d\n", name, res); 771e21c39aaSAnton Nayshtut return res; 772e21c39aaSAnton Nayshtut } 773e21c39aaSAnton Nayshtut 774e21c39aaSAnton Nayshtut skip_lookup: 775e21c39aaSAnton Nayshtut fsdev_io->u_out.readdir.name = name; 776e21c39aaSAnton Nayshtut fsdev_io->u_out.readdir.offset = nextoff; 777e21c39aaSAnton Nayshtut 778e21c39aaSAnton Nayshtut res = fsdev_io->u_in.readdir.entry_cb_fn(fsdev_io, fsdev_io->internal.cb_arg); 779e21c39aaSAnton Nayshtut if (res) { 780e21c39aaSAnton Nayshtut if (fsdev_io->u_out.readdir.fobject) { 781e21c39aaSAnton Nayshtut file_object_unref(fsdev_io->u_out.readdir.fobject, 1); 782e21c39aaSAnton Nayshtut } 783e21c39aaSAnton Nayshtut break; 784e21c39aaSAnton Nayshtut } 785e21c39aaSAnton Nayshtut 786e21c39aaSAnton Nayshtut skip_entry: 787e21c39aaSAnton Nayshtut fhandle->dir.entry = NULL; 788e21c39aaSAnton Nayshtut fhandle->dir.offset = nextoff; 789e21c39aaSAnton Nayshtut } 790e21c39aaSAnton Nayshtut 791e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "READDIR succeeded for " FOBJECT_FMT " (fh=%p, offset=%" PRIu64 ")\n", 792e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), fhandle, offset); 793e21c39aaSAnton Nayshtut return 0; 794e21c39aaSAnton Nayshtut } 795e21c39aaSAnton Nayshtut 796e21c39aaSAnton Nayshtut static int 797e21c39aaSAnton Nayshtut lo_forget(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 798e21c39aaSAnton Nayshtut { 799e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 800e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.readdir.fobject; 801e21c39aaSAnton Nayshtut uint64_t nlookup = fsdev_io->u_in.forget.nlookup; 802e21c39aaSAnton Nayshtut 803e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 804e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 805e21c39aaSAnton Nayshtut return -EINVAL; 806e21c39aaSAnton Nayshtut } 807e21c39aaSAnton Nayshtut 808e21c39aaSAnton Nayshtut file_object_unref(fobject, nlookup); 809e21c39aaSAnton Nayshtut 810e21c39aaSAnton Nayshtut return 0; 811e21c39aaSAnton Nayshtut } 812e21c39aaSAnton Nayshtut 813e21c39aaSAnton Nayshtut static uint32_t 814e21c39aaSAnton Nayshtut update_open_flags(struct aio_fsdev *vfsdev, uint32_t flags) 815e21c39aaSAnton Nayshtut { 816e21c39aaSAnton Nayshtut /* 817e21c39aaSAnton Nayshtut * With writeback cache, kernel may send read requests even 818e21c39aaSAnton Nayshtut * when userspace opened write-only 819e21c39aaSAnton Nayshtut */ 820*6cb9c75cSAnton Nayshtut if (vfsdev->mount_opts.writeback_cache_enabled && (flags & O_ACCMODE) == O_WRONLY) { 821e21c39aaSAnton Nayshtut flags &= ~O_ACCMODE; 822e21c39aaSAnton Nayshtut flags |= O_RDWR; 823e21c39aaSAnton Nayshtut } 824e21c39aaSAnton Nayshtut 825e21c39aaSAnton Nayshtut /* 826e21c39aaSAnton Nayshtut * With writeback cache, O_APPEND is handled by the kernel. 827e21c39aaSAnton Nayshtut * This breaks atomicity (since the file may change in the 828e21c39aaSAnton Nayshtut * underlying filesystem, so that the kernel's idea of the 829e21c39aaSAnton Nayshtut * end of the file isn't accurate anymore). In this example, 830e21c39aaSAnton Nayshtut * we just accept that. A more rigorous filesystem may want 831e21c39aaSAnton Nayshtut * to return an error here 832e21c39aaSAnton Nayshtut */ 833*6cb9c75cSAnton Nayshtut if (vfsdev->mount_opts.writeback_cache_enabled && (flags & O_APPEND)) { 834e21c39aaSAnton Nayshtut flags &= ~O_APPEND; 835e21c39aaSAnton Nayshtut } 836e21c39aaSAnton Nayshtut 837e21c39aaSAnton Nayshtut /* 838e21c39aaSAnton Nayshtut * O_DIRECT in guest should not necessarily mean bypassing page 839e21c39aaSAnton Nayshtut * cache on host as well. If somebody needs that behavior, it 840e21c39aaSAnton Nayshtut * probably should be a configuration knob in daemon. 841e21c39aaSAnton Nayshtut */ 842e21c39aaSAnton Nayshtut flags &= ~O_DIRECT; 843e21c39aaSAnton Nayshtut 844e21c39aaSAnton Nayshtut return flags; 845e21c39aaSAnton Nayshtut } 846e21c39aaSAnton Nayshtut 847e21c39aaSAnton Nayshtut static int 848e21c39aaSAnton Nayshtut lo_open(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 849e21c39aaSAnton Nayshtut { 850e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 851e21c39aaSAnton Nayshtut int fd, saverr; 852e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.open.fobject; 853e21c39aaSAnton Nayshtut uint32_t flags = fsdev_io->u_in.open.flags; 854e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle; 855e21c39aaSAnton Nayshtut 856e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 857e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 858e21c39aaSAnton Nayshtut return -EINVAL; 859e21c39aaSAnton Nayshtut } 860e21c39aaSAnton Nayshtut 861e21c39aaSAnton Nayshtut flags = update_open_flags(vfsdev, flags); 862e21c39aaSAnton Nayshtut 863e21c39aaSAnton Nayshtut fd = openat(vfsdev->proc_self_fd, fobject->fd_str, flags & ~O_NOFOLLOW); 864e21c39aaSAnton Nayshtut if (fd == -1) { 865e21c39aaSAnton Nayshtut saverr = -errno; 866e21c39aaSAnton Nayshtut SPDK_ERRLOG("openat(%d, %s, 0x%08" PRIx32 ") failed with err=%d\n", 867e21c39aaSAnton Nayshtut vfsdev->proc_self_fd, fobject->fd_str, flags, saverr); 868e21c39aaSAnton Nayshtut return saverr; 869e21c39aaSAnton Nayshtut } 870e21c39aaSAnton Nayshtut 871e21c39aaSAnton Nayshtut fhandle = file_handle_create(fobject, fd); 872e21c39aaSAnton Nayshtut if (!fhandle) { 873e21c39aaSAnton Nayshtut SPDK_ERRLOG("cannot create a file handle (fd=%d)\n", fd); 874e21c39aaSAnton Nayshtut close(fd); 875e21c39aaSAnton Nayshtut return -ENOMEM; 876e21c39aaSAnton Nayshtut } 877e21c39aaSAnton Nayshtut 878e21c39aaSAnton Nayshtut fsdev_io->u_out.open.fhandle = fhandle; 879e21c39aaSAnton Nayshtut 880e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "OPEN succeeded for " FOBJECT_FMT " (fh=%p, fd=%d)\n", 881e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), fhandle, fd); 882e21c39aaSAnton Nayshtut 883e21c39aaSAnton Nayshtut return 0; 884e21c39aaSAnton Nayshtut } 885e21c39aaSAnton Nayshtut 886e21c39aaSAnton Nayshtut static int 887e21c39aaSAnton Nayshtut lo_flush(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 888e21c39aaSAnton Nayshtut { 889e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 890e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.flush.fobject; 891e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.flush.fhandle; 892e21c39aaSAnton Nayshtut int res, saverr; 893e21c39aaSAnton Nayshtut 894e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 895e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 896e21c39aaSAnton Nayshtut return -EINVAL; 897e21c39aaSAnton Nayshtut } 898e21c39aaSAnton Nayshtut 899e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle)) { 900e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle: %p\n", fhandle); 901e21c39aaSAnton Nayshtut return -EINVAL; 902e21c39aaSAnton Nayshtut } 903e21c39aaSAnton Nayshtut 904e21c39aaSAnton Nayshtut res = close(dup(fhandle->fd)); 905e21c39aaSAnton Nayshtut if (res) { 906e21c39aaSAnton Nayshtut saverr = -errno; 907e21c39aaSAnton Nayshtut SPDK_ERRLOG("close(dup(%d)) failed for " FOBJECT_FMT " (fh=%p, err=%d)\n", 908e21c39aaSAnton Nayshtut fhandle->fd, FOBJECT_ARGS(fobject), fhandle, saverr); 909e21c39aaSAnton Nayshtut return saverr; 910e21c39aaSAnton Nayshtut } 911e21c39aaSAnton Nayshtut 912e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "FLUSH succeeded for " FOBJECT_FMT " (fh=%p)\n", FOBJECT_ARGS(fobject), 913e21c39aaSAnton Nayshtut fhandle); 914e21c39aaSAnton Nayshtut 915e21c39aaSAnton Nayshtut return 0; 916e21c39aaSAnton Nayshtut } 917e21c39aaSAnton Nayshtut 918e21c39aaSAnton Nayshtut static int 919e21c39aaSAnton Nayshtut lo_setattr(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 920e21c39aaSAnton Nayshtut { 921e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 922e21c39aaSAnton Nayshtut int saverr; 923e21c39aaSAnton Nayshtut int res; 924e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.setattr.fobject; 925e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.setattr.fhandle; 926e21c39aaSAnton Nayshtut uint32_t to_set = fsdev_io->u_in.setattr.to_set; 927e21c39aaSAnton Nayshtut struct spdk_fsdev_file_attr *attr = &fsdev_io->u_in.setattr.attr; 928e21c39aaSAnton Nayshtut 929e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 930e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 931e21c39aaSAnton Nayshtut return -EINVAL; 932e21c39aaSAnton Nayshtut } 933e21c39aaSAnton Nayshtut 934e21c39aaSAnton Nayshtut if (to_set & FSDEV_SET_ATTR_MODE) { 935e21c39aaSAnton Nayshtut if (fhandle) { 936e21c39aaSAnton Nayshtut res = fchmod(fhandle->fd, attr->mode); 937e21c39aaSAnton Nayshtut } else { 938e21c39aaSAnton Nayshtut res = fchmodat(vfsdev->proc_self_fd, fobject->fd_str, attr->mode, 0); 939e21c39aaSAnton Nayshtut } 940e21c39aaSAnton Nayshtut if (res == -1) { 941e21c39aaSAnton Nayshtut saverr = -errno; 942e21c39aaSAnton Nayshtut SPDK_ERRLOG("fchmod failed for " FOBJECT_FMT "\n", FOBJECT_ARGS(fobject)); 943e21c39aaSAnton Nayshtut return saverr; 944e21c39aaSAnton Nayshtut } 945e21c39aaSAnton Nayshtut } 946e21c39aaSAnton Nayshtut 947e21c39aaSAnton Nayshtut if (to_set & (FSDEV_SET_ATTR_UID | FSDEV_SET_ATTR_GID)) { 948e21c39aaSAnton Nayshtut uid_t uid = (to_set & FSDEV_SET_ATTR_UID) ? attr->uid : (uid_t) -1; 949e21c39aaSAnton Nayshtut gid_t gid = (to_set & FSDEV_SET_ATTR_GID) ? attr->gid : (gid_t) -1; 950e21c39aaSAnton Nayshtut 951e21c39aaSAnton Nayshtut res = fchownat(fobject->fd, "", uid, gid, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); 952e21c39aaSAnton Nayshtut if (res == -1) { 953e21c39aaSAnton Nayshtut saverr = -errno; 954e21c39aaSAnton Nayshtut SPDK_ERRLOG("fchownat failed for " FOBJECT_FMT "\n", FOBJECT_ARGS(fobject)); 955e21c39aaSAnton Nayshtut return saverr; 956e21c39aaSAnton Nayshtut } 957e21c39aaSAnton Nayshtut } 958e21c39aaSAnton Nayshtut 959e21c39aaSAnton Nayshtut if (to_set & FSDEV_SET_ATTR_SIZE) { 960e21c39aaSAnton Nayshtut int truncfd; 961e21c39aaSAnton Nayshtut 962e21c39aaSAnton Nayshtut if (fhandle) { 963e21c39aaSAnton Nayshtut truncfd = fhandle->fd; 964e21c39aaSAnton Nayshtut } else { 965e21c39aaSAnton Nayshtut truncfd = openat(vfsdev->proc_self_fd, fobject->fd_str, O_RDWR); 966e21c39aaSAnton Nayshtut if (truncfd < 0) { 967e21c39aaSAnton Nayshtut saverr = -errno; 968e21c39aaSAnton Nayshtut SPDK_ERRLOG("openat failed for " FOBJECT_FMT "\n", FOBJECT_ARGS(fobject)); 969e21c39aaSAnton Nayshtut return saverr; 970e21c39aaSAnton Nayshtut } 971e21c39aaSAnton Nayshtut } 972e21c39aaSAnton Nayshtut 973e21c39aaSAnton Nayshtut res = ftruncate(truncfd, attr->size); 974e21c39aaSAnton Nayshtut if (!fhandle) { 975e21c39aaSAnton Nayshtut saverr = -errno; 976e21c39aaSAnton Nayshtut close(truncfd); 977e21c39aaSAnton Nayshtut errno = saverr; 978e21c39aaSAnton Nayshtut } 979e21c39aaSAnton Nayshtut if (res == -1) { 980e21c39aaSAnton Nayshtut saverr = -errno; 981e21c39aaSAnton Nayshtut SPDK_ERRLOG("ftruncate failed for " FOBJECT_FMT " (size=%" PRIu64 ")\n", FOBJECT_ARGS(fobject), 982e21c39aaSAnton Nayshtut attr->size); 983e21c39aaSAnton Nayshtut return saverr; 984e21c39aaSAnton Nayshtut } 985e21c39aaSAnton Nayshtut } 986e21c39aaSAnton Nayshtut 987e21c39aaSAnton Nayshtut if (to_set & (FSDEV_SET_ATTR_ATIME | FSDEV_SET_ATTR_MTIME)) { 988e21c39aaSAnton Nayshtut struct timespec tv[2]; 989e21c39aaSAnton Nayshtut 990e21c39aaSAnton Nayshtut tv[0].tv_sec = 0; 991e21c39aaSAnton Nayshtut tv[1].tv_sec = 0; 992e21c39aaSAnton Nayshtut tv[0].tv_nsec = UTIME_OMIT; 993e21c39aaSAnton Nayshtut tv[1].tv_nsec = UTIME_OMIT; 994e21c39aaSAnton Nayshtut 995e21c39aaSAnton Nayshtut if (to_set & FSDEV_SET_ATTR_ATIME_NOW) { 996e21c39aaSAnton Nayshtut tv[0].tv_nsec = UTIME_NOW; 997e21c39aaSAnton Nayshtut } else if (to_set & FSDEV_SET_ATTR_ATIME) { 998e21c39aaSAnton Nayshtut tv[0].tv_sec = attr->atime; 999e21c39aaSAnton Nayshtut tv[0].tv_nsec = attr->atimensec; 1000e21c39aaSAnton Nayshtut } 1001e21c39aaSAnton Nayshtut 1002e21c39aaSAnton Nayshtut if (to_set & FSDEV_SET_ATTR_MTIME_NOW) { 1003e21c39aaSAnton Nayshtut tv[1].tv_nsec = UTIME_NOW; 1004e21c39aaSAnton Nayshtut } else if (to_set & FSDEV_SET_ATTR_MTIME) { 1005e21c39aaSAnton Nayshtut tv[1].tv_sec = attr->mtime; 1006e21c39aaSAnton Nayshtut tv[1].tv_nsec = attr->mtimensec; 1007e21c39aaSAnton Nayshtut } 1008e21c39aaSAnton Nayshtut 1009e21c39aaSAnton Nayshtut if (fhandle) { 1010e21c39aaSAnton Nayshtut res = futimens(fhandle->fd, tv); 1011e21c39aaSAnton Nayshtut } else { 1012e21c39aaSAnton Nayshtut res = utimensat_empty(vfsdev, fobject, tv); 1013e21c39aaSAnton Nayshtut } 1014e21c39aaSAnton Nayshtut if (res == -1) { 1015e21c39aaSAnton Nayshtut saverr = -errno; 1016e21c39aaSAnton Nayshtut SPDK_ERRLOG("futimens/utimensat_empty failed for " FOBJECT_FMT "\n", 1017e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject)); 1018e21c39aaSAnton Nayshtut return saverr; 1019e21c39aaSAnton Nayshtut } 1020e21c39aaSAnton Nayshtut } 1021e21c39aaSAnton Nayshtut 1022e21c39aaSAnton Nayshtut res = file_object_fill_attr(fobject, &fsdev_io->u_out.setattr.attr); 1023e21c39aaSAnton Nayshtut if (res) { 1024e21c39aaSAnton Nayshtut SPDK_ERRLOG("file_object_fill_attr failed for " FOBJECT_FMT "\n", 1025e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject)); 1026e21c39aaSAnton Nayshtut return res; 1027e21c39aaSAnton Nayshtut } 1028e21c39aaSAnton Nayshtut 1029e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "SETATTR succeeded for " FOBJECT_FMT "\n", 1030e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject)); 1031e21c39aaSAnton Nayshtut 1032e21c39aaSAnton Nayshtut return 0; 1033e21c39aaSAnton Nayshtut } 1034e21c39aaSAnton Nayshtut 1035e21c39aaSAnton Nayshtut static int 1036e21c39aaSAnton Nayshtut lo_create(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1037e21c39aaSAnton Nayshtut { 1038e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1039e21c39aaSAnton Nayshtut int fd; 1040e21c39aaSAnton Nayshtut int err; 1041e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject = fsdev_io->u_in.create.parent_fobject; 1042e21c39aaSAnton Nayshtut const char *name = fsdev_io->u_in.create.name; 1043e21c39aaSAnton Nayshtut uint32_t mode = fsdev_io->u_in.create.mode; 1044e21c39aaSAnton Nayshtut uint32_t flags = fsdev_io->u_in.create.flags; 1045e21c39aaSAnton Nayshtut uint32_t umask = fsdev_io->u_in.create.umask; 1046e21c39aaSAnton Nayshtut struct lo_cred old_cred, new_cred = { 1047e21c39aaSAnton Nayshtut .euid = fsdev_io->u_in.create.euid, 1048e21c39aaSAnton Nayshtut .egid = fsdev_io->u_in.create.egid, 1049e21c39aaSAnton Nayshtut }; 1050e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject; 1051e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle; 1052e21c39aaSAnton Nayshtut struct spdk_fsdev_file_attr *attr = &fsdev_io->u_out.create.attr; 1053e21c39aaSAnton Nayshtut 1054e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, parent_fobject)) { 1055e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid parent_fobject: %p\n", parent_fobject); 1056e21c39aaSAnton Nayshtut return -EINVAL; 1057e21c39aaSAnton Nayshtut } 1058e21c39aaSAnton Nayshtut 1059e21c39aaSAnton Nayshtut UNUSED(umask); 1060e21c39aaSAnton Nayshtut 1061e21c39aaSAnton Nayshtut if (!is_safe_path_component(name)) { 1062e21c39aaSAnton Nayshtut SPDK_ERRLOG("CREATE: %s not a safe component\n", name); 1063e21c39aaSAnton Nayshtut return -EINVAL; 1064e21c39aaSAnton Nayshtut } 1065e21c39aaSAnton Nayshtut 1066e21c39aaSAnton Nayshtut err = lo_change_cred(&new_cred, &old_cred); 1067e21c39aaSAnton Nayshtut if (err) { 1068e21c39aaSAnton Nayshtut SPDK_ERRLOG("CREATE: cannot change credentials\n"); 1069e21c39aaSAnton Nayshtut return err; 1070e21c39aaSAnton Nayshtut } 1071e21c39aaSAnton Nayshtut 1072e21c39aaSAnton Nayshtut flags = update_open_flags(vfsdev, flags); 1073e21c39aaSAnton Nayshtut 1074e21c39aaSAnton Nayshtut fd = openat(parent_fobject->fd, name, (flags | O_CREAT) & ~O_NOFOLLOW, mode); 1075e21c39aaSAnton Nayshtut err = fd == -1 ? -errno : 0; 1076e21c39aaSAnton Nayshtut lo_restore_cred(&old_cred); 1077e21c39aaSAnton Nayshtut 1078e21c39aaSAnton Nayshtut if (err) { 1079e21c39aaSAnton Nayshtut SPDK_ERRLOG("CREATE: openat failed with %d\n", err); 1080e21c39aaSAnton Nayshtut return err; 1081e21c39aaSAnton Nayshtut } 1082e21c39aaSAnton Nayshtut 1083e21c39aaSAnton Nayshtut err = lo_do_lookup(vfsdev, parent_fobject, name, &fobject, attr); 1084e21c39aaSAnton Nayshtut if (err) { 1085e21c39aaSAnton Nayshtut SPDK_ERRLOG("CREATE: lookup failed with %d\n", err); 1086e21c39aaSAnton Nayshtut return err; 1087e21c39aaSAnton Nayshtut } 1088e21c39aaSAnton Nayshtut 1089e21c39aaSAnton Nayshtut fhandle = file_handle_create(fobject, fd); 1090e21c39aaSAnton Nayshtut if (!fhandle) { 1091e21c39aaSAnton Nayshtut SPDK_ERRLOG("cannot create a file handle (fd=%d)\n", fd); 1092e21c39aaSAnton Nayshtut close(fd); 1093e21c39aaSAnton Nayshtut file_object_unref(fobject, 1); 1094e21c39aaSAnton Nayshtut return -ENOMEM; 1095e21c39aaSAnton Nayshtut } 1096e21c39aaSAnton Nayshtut 1097e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "CREATE: succeeded (name=%s " FOBJECT_FMT " fh=%p)\n", 1098e21c39aaSAnton Nayshtut name, FOBJECT_ARGS(fobject), fhandle); 1099e21c39aaSAnton Nayshtut 1100e21c39aaSAnton Nayshtut fsdev_io->u_out.create.fobject = fobject; 1101e21c39aaSAnton Nayshtut fsdev_io->u_out.create.fhandle = fhandle; 1102e21c39aaSAnton Nayshtut 1103e21c39aaSAnton Nayshtut return 0; 1104e21c39aaSAnton Nayshtut } 1105e21c39aaSAnton Nayshtut 1106e21c39aaSAnton Nayshtut static int 1107e21c39aaSAnton Nayshtut lo_release(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1108e21c39aaSAnton Nayshtut { 1109e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1110e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.release.fobject; 1111e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.release.fhandle; 1112e21c39aaSAnton Nayshtut 1113e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1114e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1115e21c39aaSAnton Nayshtut return -EINVAL; 1116e21c39aaSAnton Nayshtut } 1117e21c39aaSAnton Nayshtut 1118e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle)) { 1119e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle: %p\n", fhandle); 1120e21c39aaSAnton Nayshtut return -EINVAL; 1121e21c39aaSAnton Nayshtut } 1122e21c39aaSAnton Nayshtut 1123e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "RELEASE succeeded for " FOBJECT_FMT " fh=%p)\n", 1124e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), fhandle); 112556e509c8SMarcin Spiewak 112656e509c8SMarcin Spiewak file_handle_delete(fhandle); 112756e509c8SMarcin Spiewak 1128e21c39aaSAnton Nayshtut return 0; 1129e21c39aaSAnton Nayshtut } 1130e21c39aaSAnton Nayshtut 1131e21c39aaSAnton Nayshtut static void 1132e21c39aaSAnton Nayshtut lo_read_cb(void *ctx, uint32_t data_size, int error) 1133e21c39aaSAnton Nayshtut { 1134e21c39aaSAnton Nayshtut struct spdk_fsdev_io *fsdev_io = ctx; 1135e21c39aaSAnton Nayshtut struct aio_fsdev_io *vfsdev_io = fsdev_to_aio_io(fsdev_io); 1136e21c39aaSAnton Nayshtut 1137e21c39aaSAnton Nayshtut if (vfsdev_io->aio) { 1138e21c39aaSAnton Nayshtut TAILQ_REMOVE(&vfsdev_io->ch->ios_in_progress, vfsdev_io, link); 1139e21c39aaSAnton Nayshtut } 1140e21c39aaSAnton Nayshtut 1141e21c39aaSAnton Nayshtut fsdev_io->u_out.read.data_size = data_size; 1142e21c39aaSAnton Nayshtut 1143e21c39aaSAnton Nayshtut spdk_fsdev_io_complete(fsdev_io, error); 1144e21c39aaSAnton Nayshtut } 1145e21c39aaSAnton Nayshtut 1146e21c39aaSAnton Nayshtut static int 1147e21c39aaSAnton Nayshtut lo_read(struct spdk_io_channel *_ch, struct spdk_fsdev_io *fsdev_io) 1148e21c39aaSAnton Nayshtut { 1149e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1150e21c39aaSAnton Nayshtut struct aio_io_channel *ch = spdk_io_channel_get_ctx(_ch); 1151e21c39aaSAnton Nayshtut struct aio_fsdev_io *vfsdev_io = fsdev_to_aio_io(fsdev_io); 1152e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.read.fobject; 1153e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.read.fhandle; 1154e21c39aaSAnton Nayshtut size_t size = fsdev_io->u_in.read.size; 1155e21c39aaSAnton Nayshtut uint64_t offs = fsdev_io->u_in.read.offs; 1156e21c39aaSAnton Nayshtut uint32_t flags = fsdev_io->u_in.read.flags; 1157e21c39aaSAnton Nayshtut struct iovec *outvec = fsdev_io->u_in.read.iov; 1158e21c39aaSAnton Nayshtut uint32_t outcnt = fsdev_io->u_in.read.iovcnt; 1159e21c39aaSAnton Nayshtut 1160e21c39aaSAnton Nayshtut /* we don't suport the memory domains at the moment */ 1161e21c39aaSAnton Nayshtut assert(!fsdev_io->u_in.read.opts || !fsdev_io->u_in.read.opts->memory_domain); 1162e21c39aaSAnton Nayshtut 1163e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1164e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1165e21c39aaSAnton Nayshtut return -EINVAL; 1166e21c39aaSAnton Nayshtut } 1167e21c39aaSAnton Nayshtut 1168e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle)) { 1169e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle: %p\n", fhandle); 1170e21c39aaSAnton Nayshtut return -EINVAL; 1171e21c39aaSAnton Nayshtut } 1172e21c39aaSAnton Nayshtut 1173e21c39aaSAnton Nayshtut UNUSED(flags); 1174e21c39aaSAnton Nayshtut 1175e21c39aaSAnton Nayshtut if (!outcnt || !outvec) { 1176e21c39aaSAnton Nayshtut SPDK_ERRLOG("bad outvec: iov=%p outcnt=%" PRIu32 "\n", outvec, outcnt); 1177e21c39aaSAnton Nayshtut return -EINVAL; 1178e21c39aaSAnton Nayshtut } 1179e21c39aaSAnton Nayshtut 118092108e0aSYoray Zack if (vfsdev->skip_rw) { 118192108e0aSYoray Zack uint32_t i; 118292108e0aSYoray Zack 118392108e0aSYoray Zack fsdev_io->u_out.read.data_size = 0; 118492108e0aSYoray Zack 118592108e0aSYoray Zack for (i = 0; i < outcnt; i++, outvec++) { 118692108e0aSYoray Zack fsdev_io->u_out.read.data_size += outvec->iov_len; 118792108e0aSYoray Zack } 118892108e0aSYoray Zack 118992108e0aSYoray Zack TAILQ_INSERT_TAIL(&ch->ios_to_complete, vfsdev_io, link); 119092108e0aSYoray Zack 119192108e0aSYoray Zack return IO_STATUS_ASYNC; 119292108e0aSYoray Zack } 119392108e0aSYoray Zack 1194e21c39aaSAnton Nayshtut vfsdev_io->aio = spdk_aio_mgr_read(ch->mgr, lo_read_cb, fsdev_io, fhandle->fd, offs, size, outvec, 1195e21c39aaSAnton Nayshtut outcnt); 1196e21c39aaSAnton Nayshtut if (vfsdev_io->aio) { 1197e21c39aaSAnton Nayshtut vfsdev_io->ch = ch; 1198e21c39aaSAnton Nayshtut TAILQ_INSERT_TAIL(&ch->ios_in_progress, vfsdev_io, link); 1199e21c39aaSAnton Nayshtut } 1200e21c39aaSAnton Nayshtut 1201e21c39aaSAnton Nayshtut return IO_STATUS_ASYNC; 1202e21c39aaSAnton Nayshtut } 1203e21c39aaSAnton Nayshtut 1204e21c39aaSAnton Nayshtut static void 1205e21c39aaSAnton Nayshtut lo_write_cb(void *ctx, uint32_t data_size, int error) 1206e21c39aaSAnton Nayshtut { 1207e21c39aaSAnton Nayshtut struct spdk_fsdev_io *fsdev_io = ctx; 1208e21c39aaSAnton Nayshtut struct aio_fsdev_io *vfsdev_io = fsdev_to_aio_io(fsdev_io); 1209e21c39aaSAnton Nayshtut 1210e21c39aaSAnton Nayshtut if (vfsdev_io->aio) { 1211e21c39aaSAnton Nayshtut TAILQ_REMOVE(&vfsdev_io->ch->ios_in_progress, vfsdev_io, link); 1212e21c39aaSAnton Nayshtut } 1213e21c39aaSAnton Nayshtut 1214e21c39aaSAnton Nayshtut fsdev_io->u_out.write.data_size = data_size; 1215e21c39aaSAnton Nayshtut 1216e21c39aaSAnton Nayshtut spdk_fsdev_io_complete(fsdev_io, error); 1217e21c39aaSAnton Nayshtut } 1218e21c39aaSAnton Nayshtut 1219e21c39aaSAnton Nayshtut static int 1220e21c39aaSAnton Nayshtut lo_write(struct spdk_io_channel *_ch, struct spdk_fsdev_io *fsdev_io) 1221e21c39aaSAnton Nayshtut { 1222e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1223e21c39aaSAnton Nayshtut struct aio_io_channel *ch = spdk_io_channel_get_ctx(_ch); 1224e21c39aaSAnton Nayshtut struct aio_fsdev_io *vfsdev_io = fsdev_to_aio_io(fsdev_io); 1225e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.write.fobject; 1226e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.write.fhandle; 1227e21c39aaSAnton Nayshtut size_t size = fsdev_io->u_in.write.size; 1228e21c39aaSAnton Nayshtut uint64_t offs = fsdev_io->u_in.write.offs; 1229e21c39aaSAnton Nayshtut uint32_t flags = fsdev_io->u_in.write.flags; 1230e21c39aaSAnton Nayshtut const struct iovec *invec = fsdev_io->u_in.write.iov; 1231e21c39aaSAnton Nayshtut uint32_t incnt = fsdev_io->u_in.write.iovcnt; 1232e21c39aaSAnton Nayshtut 1233e21c39aaSAnton Nayshtut /* we don't suport the memory domains at the moment */ 1234e21c39aaSAnton Nayshtut assert(!fsdev_io->u_in.write.opts || !fsdev_io->u_in.write.opts->memory_domain); 1235e21c39aaSAnton Nayshtut 1236e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1237e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1238e21c39aaSAnton Nayshtut return -EINVAL; 1239e21c39aaSAnton Nayshtut } 1240e21c39aaSAnton Nayshtut 1241e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle)) { 1242e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle: %p\n", fhandle); 1243e21c39aaSAnton Nayshtut return -EINVAL; 1244e21c39aaSAnton Nayshtut } 1245e21c39aaSAnton Nayshtut 1246e21c39aaSAnton Nayshtut UNUSED(flags); 1247e21c39aaSAnton Nayshtut 1248e21c39aaSAnton Nayshtut if (!incnt || !invec) { /* there should be at least one iovec with data */ 1249e21c39aaSAnton Nayshtut SPDK_ERRLOG("bad invec: iov=%p cnt=%" PRIu32 "\n", invec, incnt); 1250e21c39aaSAnton Nayshtut return -EINVAL; 1251e21c39aaSAnton Nayshtut } 1252e21c39aaSAnton Nayshtut 125392108e0aSYoray Zack if (vfsdev->skip_rw) { 125492108e0aSYoray Zack uint32_t i; 125592108e0aSYoray Zack 125692108e0aSYoray Zack fsdev_io->u_out.write.data_size = 0; 125792108e0aSYoray Zack for (i = 0; i < incnt; i++, invec++) { 125892108e0aSYoray Zack fsdev_io->u_out.write.data_size += invec->iov_len; 125992108e0aSYoray Zack } 126092108e0aSYoray Zack 126192108e0aSYoray Zack TAILQ_INSERT_TAIL(&ch->ios_to_complete, vfsdev_io, link); 126292108e0aSYoray Zack 126392108e0aSYoray Zack return IO_STATUS_ASYNC; 126492108e0aSYoray Zack } 126592108e0aSYoray Zack 1266e21c39aaSAnton Nayshtut vfsdev_io->aio = spdk_aio_mgr_write(ch->mgr, lo_write_cb, fsdev_io, 1267e21c39aaSAnton Nayshtut fhandle->fd, offs, size, invec, incnt); 1268e21c39aaSAnton Nayshtut if (vfsdev_io->aio) { 1269e21c39aaSAnton Nayshtut vfsdev_io->ch = ch; 1270e21c39aaSAnton Nayshtut TAILQ_INSERT_TAIL(&ch->ios_in_progress, vfsdev_io, link); 1271e21c39aaSAnton Nayshtut } 1272e21c39aaSAnton Nayshtut 1273e21c39aaSAnton Nayshtut return IO_STATUS_ASYNC; 1274e21c39aaSAnton Nayshtut } 1275e21c39aaSAnton Nayshtut 1276e21c39aaSAnton Nayshtut static int 1277e21c39aaSAnton Nayshtut lo_readlink(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1278e21c39aaSAnton Nayshtut { 1279e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1280e21c39aaSAnton Nayshtut int res; 1281e21c39aaSAnton Nayshtut char *buf; 1282e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.readlink.fobject; 1283e21c39aaSAnton Nayshtut 1284e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1285e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1286e21c39aaSAnton Nayshtut return -EINVAL; 1287e21c39aaSAnton Nayshtut } 1288e21c39aaSAnton Nayshtut 1289e21c39aaSAnton Nayshtut buf = malloc(PATH_MAX + 1); 1290e21c39aaSAnton Nayshtut if (!buf) { 1291e21c39aaSAnton Nayshtut SPDK_ERRLOG("malloc(%zu) failed\n", (size_t)(PATH_MAX + 1)); 1292e21c39aaSAnton Nayshtut return -ENOMEM; 1293e21c39aaSAnton Nayshtut } 1294e21c39aaSAnton Nayshtut 1295e21c39aaSAnton Nayshtut res = readlinkat(fobject->fd, "", buf, PATH_MAX + 1); 1296e21c39aaSAnton Nayshtut if (res == -1) { 1297e21c39aaSAnton Nayshtut int saverr = -errno; 1298e21c39aaSAnton Nayshtut SPDK_ERRLOG("readlinkat failed for " FOBJECT_FMT " with %d\n", 1299e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), saverr); 1300e21c39aaSAnton Nayshtut free(buf); 1301e21c39aaSAnton Nayshtut return saverr; 1302e21c39aaSAnton Nayshtut } 1303e21c39aaSAnton Nayshtut 1304e21c39aaSAnton Nayshtut if (((uint32_t)res) == PATH_MAX + 1) { 1305e21c39aaSAnton Nayshtut SPDK_ERRLOG("buffer is too short\n"); 1306e21c39aaSAnton Nayshtut free(buf); 1307e21c39aaSAnton Nayshtut return -ENAMETOOLONG; 1308e21c39aaSAnton Nayshtut } 1309e21c39aaSAnton Nayshtut 1310e21c39aaSAnton Nayshtut buf[res] = 0; 1311e21c39aaSAnton Nayshtut fsdev_io->u_out.readlink.linkname = buf; 1312e21c39aaSAnton Nayshtut 1313e21c39aaSAnton Nayshtut return 0; 1314e21c39aaSAnton Nayshtut } 1315e21c39aaSAnton Nayshtut 1316e21c39aaSAnton Nayshtut static int 1317e21c39aaSAnton Nayshtut lo_statfs(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1318e21c39aaSAnton Nayshtut { 1319e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1320e21c39aaSAnton Nayshtut int res; 1321e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.statfs.fobject; 1322e21c39aaSAnton Nayshtut struct statvfs stbuf; 1323e21c39aaSAnton Nayshtut 1324e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1325e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1326e21c39aaSAnton Nayshtut return -EINVAL; 1327e21c39aaSAnton Nayshtut } 1328e21c39aaSAnton Nayshtut 1329e21c39aaSAnton Nayshtut res = fstatvfs(fobject->fd, &stbuf); 1330e21c39aaSAnton Nayshtut if (res == -1) { 1331e21c39aaSAnton Nayshtut int saverr = -errno; 1332e21c39aaSAnton Nayshtut SPDK_ERRLOG("fstatvfs failed with %d\n", saverr); 1333e21c39aaSAnton Nayshtut return saverr; 1334e21c39aaSAnton Nayshtut } 1335e21c39aaSAnton Nayshtut 1336e21c39aaSAnton Nayshtut fsdev_io->u_out.statfs.statfs.blocks = stbuf.f_blocks; 1337e21c39aaSAnton Nayshtut fsdev_io->u_out.statfs.statfs.bfree = stbuf.f_bfree; 1338e21c39aaSAnton Nayshtut fsdev_io->u_out.statfs.statfs.bavail = stbuf.f_bavail; 1339e21c39aaSAnton Nayshtut fsdev_io->u_out.statfs.statfs.files = stbuf.f_files; 1340e21c39aaSAnton Nayshtut fsdev_io->u_out.statfs.statfs.ffree = stbuf.f_ffree; 1341e21c39aaSAnton Nayshtut fsdev_io->u_out.statfs.statfs.bsize = stbuf.f_bsize; 1342e21c39aaSAnton Nayshtut fsdev_io->u_out.statfs.statfs.namelen = stbuf.f_namemax; 1343e21c39aaSAnton Nayshtut fsdev_io->u_out.statfs.statfs.frsize = stbuf.f_frsize; 1344e21c39aaSAnton Nayshtut 1345e21c39aaSAnton Nayshtut return 0; 1346e21c39aaSAnton Nayshtut } 1347e21c39aaSAnton Nayshtut 1348e21c39aaSAnton Nayshtut static int 1349e21c39aaSAnton Nayshtut lo_mknod_symlink(struct spdk_fsdev_io *fsdev_io, struct spdk_fsdev_file_object *parent_fobject, 1350e21c39aaSAnton Nayshtut const char *name, mode_t mode, dev_t rdev, const char *link, uid_t euid, gid_t egid, 1351e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object **pfobject, struct spdk_fsdev_file_attr *attr) 1352e21c39aaSAnton Nayshtut { 1353e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1354e21c39aaSAnton Nayshtut int res; 1355e21c39aaSAnton Nayshtut int saverr; 1356e21c39aaSAnton Nayshtut struct lo_cred old_cred, new_cred = { 1357e21c39aaSAnton Nayshtut .euid = euid, 1358e21c39aaSAnton Nayshtut .egid = egid, 1359e21c39aaSAnton Nayshtut }; 1360e21c39aaSAnton Nayshtut 1361e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, parent_fobject)) { 1362e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid parent_fobject: %p\n", parent_fobject); 1363e21c39aaSAnton Nayshtut return -EINVAL; 1364e21c39aaSAnton Nayshtut } 1365e21c39aaSAnton Nayshtut 1366e21c39aaSAnton Nayshtut if (!is_safe_path_component(name)) { 1367e21c39aaSAnton Nayshtut SPDK_ERRLOG("%s isn'h safe\n", name); 1368e21c39aaSAnton Nayshtut return -EINVAL; 1369e21c39aaSAnton Nayshtut } 1370e21c39aaSAnton Nayshtut 1371e21c39aaSAnton Nayshtut res = lo_change_cred(&new_cred, &old_cred); 1372e21c39aaSAnton Nayshtut if (res) { 1373e21c39aaSAnton Nayshtut SPDK_ERRLOG("cannot change cred (err=%d)\n", res); 1374e21c39aaSAnton Nayshtut return res; 1375e21c39aaSAnton Nayshtut } 1376e21c39aaSAnton Nayshtut 1377e21c39aaSAnton Nayshtut if (S_ISDIR(mode)) { 1378e21c39aaSAnton Nayshtut res = mkdirat(parent_fobject->fd, name, mode); 1379e21c39aaSAnton Nayshtut } else if (S_ISLNK(mode)) { 1380e21c39aaSAnton Nayshtut if (link) { 1381e21c39aaSAnton Nayshtut res = symlinkat(link, parent_fobject->fd, name); 1382e21c39aaSAnton Nayshtut } else { 1383e21c39aaSAnton Nayshtut SPDK_ERRLOG("NULL link pointer\n"); 1384e21c39aaSAnton Nayshtut errno = EINVAL; 1385e21c39aaSAnton Nayshtut } 1386e21c39aaSAnton Nayshtut } else { 1387e21c39aaSAnton Nayshtut res = mknodat(parent_fobject->fd, name, mode, rdev); 1388e21c39aaSAnton Nayshtut } 1389e21c39aaSAnton Nayshtut saverr = -errno; 1390e21c39aaSAnton Nayshtut 1391e21c39aaSAnton Nayshtut lo_restore_cred(&old_cred); 1392e21c39aaSAnton Nayshtut 1393e21c39aaSAnton Nayshtut if (res == -1) { 1394e21c39aaSAnton Nayshtut SPDK_ERRLOG("cannot mkdirat/symlinkat/mknodat (err=%d)\n", saverr); 1395e21c39aaSAnton Nayshtut return saverr; 1396e21c39aaSAnton Nayshtut } 1397e21c39aaSAnton Nayshtut 1398e21c39aaSAnton Nayshtut res = lo_do_lookup(vfsdev, parent_fobject, name, pfobject, attr); 1399e21c39aaSAnton Nayshtut if (res) { 1400e21c39aaSAnton Nayshtut SPDK_ERRLOG("lookup failed (err=%d)\n", res); 1401e21c39aaSAnton Nayshtut return res; 1402e21c39aaSAnton Nayshtut } 1403e21c39aaSAnton Nayshtut 1404e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "lo_mknod_symlink(" FOBJECT_FMT "/%s -> " FOBJECT_FMT "\n", 1405e21c39aaSAnton Nayshtut FOBJECT_ARGS(parent_fobject), name, FOBJECT_ARGS(*pfobject)); 1406e21c39aaSAnton Nayshtut 1407e21c39aaSAnton Nayshtut return 0; 1408e21c39aaSAnton Nayshtut } 1409e21c39aaSAnton Nayshtut 1410e21c39aaSAnton Nayshtut static int 1411e21c39aaSAnton Nayshtut lo_mknod(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1412e21c39aaSAnton Nayshtut { 1413e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject = fsdev_io->u_in.mknod.parent_fobject; 1414e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.mknod.name; 1415e21c39aaSAnton Nayshtut mode_t mode = fsdev_io->u_in.mknod.mode; 1416e21c39aaSAnton Nayshtut dev_t rdev = fsdev_io->u_in.mknod.rdev; 1417e21c39aaSAnton Nayshtut uid_t euid = fsdev_io->u_in.mknod.euid; 1418e21c39aaSAnton Nayshtut gid_t egid = fsdev_io->u_in.mknod.egid; 1419e21c39aaSAnton Nayshtut 1420e21c39aaSAnton Nayshtut return lo_mknod_symlink(fsdev_io, parent_fobject, name, mode, rdev, NULL, euid, egid, 1421e21c39aaSAnton Nayshtut &fsdev_io->u_out.mknod.fobject, &fsdev_io->u_out.mknod.attr); 1422e21c39aaSAnton Nayshtut } 1423e21c39aaSAnton Nayshtut 1424e21c39aaSAnton Nayshtut static int 1425e21c39aaSAnton Nayshtut lo_mkdir(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1426e21c39aaSAnton Nayshtut { 1427e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject = fsdev_io->u_in.mkdir.parent_fobject; 1428e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.mkdir.name; 1429e21c39aaSAnton Nayshtut mode_t mode = fsdev_io->u_in.mkdir.mode; 1430e21c39aaSAnton Nayshtut uid_t euid = fsdev_io->u_in.mkdir.euid; 1431e21c39aaSAnton Nayshtut gid_t egid = fsdev_io->u_in.mkdir.egid; 1432e21c39aaSAnton Nayshtut 1433e21c39aaSAnton Nayshtut return lo_mknod_symlink(fsdev_io, parent_fobject, name, S_IFDIR | mode, 0, NULL, euid, egid, 1434e21c39aaSAnton Nayshtut &fsdev_io->u_out.mkdir.fobject, &fsdev_io->u_out.mkdir.attr); 1435e21c39aaSAnton Nayshtut } 1436e21c39aaSAnton Nayshtut 1437e21c39aaSAnton Nayshtut static int 1438e21c39aaSAnton Nayshtut lo_symlink(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1439e21c39aaSAnton Nayshtut { 1440e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject = fsdev_io->u_in.symlink.parent_fobject; 1441e21c39aaSAnton Nayshtut char *target = fsdev_io->u_in.symlink.target; 1442e21c39aaSAnton Nayshtut char *linkpath = fsdev_io->u_in.symlink.linkpath; 1443e21c39aaSAnton Nayshtut uid_t euid = fsdev_io->u_in.symlink.euid; 1444e21c39aaSAnton Nayshtut gid_t egid = fsdev_io->u_in.symlink.egid; 1445e21c39aaSAnton Nayshtut 1446e21c39aaSAnton Nayshtut return lo_mknod_symlink(fsdev_io, parent_fobject, target, S_IFLNK, 0, linkpath, euid, egid, 1447e21c39aaSAnton Nayshtut &fsdev_io->u_out.symlink.fobject, &fsdev_io->u_out.symlink.attr); 1448e21c39aaSAnton Nayshtut } 1449e21c39aaSAnton Nayshtut 1450e21c39aaSAnton Nayshtut static int 1451e21c39aaSAnton Nayshtut lo_do_unlink(struct aio_fsdev *vfsdev, struct spdk_fsdev_file_object *parent_fobject, 1452e21c39aaSAnton Nayshtut const char *name, bool is_dir) 1453e21c39aaSAnton Nayshtut { 1454e21c39aaSAnton Nayshtut /* fobject must be initialized to avoid a scan-build false positive */ 1455e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = NULL; 1456e21c39aaSAnton Nayshtut int res; 1457e21c39aaSAnton Nayshtut 1458e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, parent_fobject)) { 1459e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid parent_fobject: %p\n", parent_fobject); 1460e21c39aaSAnton Nayshtut return -EINVAL; 1461e21c39aaSAnton Nayshtut } 1462e21c39aaSAnton Nayshtut 1463e21c39aaSAnton Nayshtut if (!is_safe_path_component(name)) { 1464e21c39aaSAnton Nayshtut SPDK_ERRLOG("%s isn't safe\n", name); 1465e21c39aaSAnton Nayshtut return -EINVAL; 1466e21c39aaSAnton Nayshtut } 1467e21c39aaSAnton Nayshtut 1468e21c39aaSAnton Nayshtut res = lo_do_lookup(vfsdev, parent_fobject, name, &fobject, NULL); 1469e21c39aaSAnton Nayshtut if (res) { 1470e21c39aaSAnton Nayshtut SPDK_ERRLOG("can't find '%s' under " FOBJECT_FMT "\n", name, FOBJECT_ARGS(parent_fobject)); 1471e21c39aaSAnton Nayshtut return -EIO; 1472e21c39aaSAnton Nayshtut } 1473e21c39aaSAnton Nayshtut 1474e21c39aaSAnton Nayshtut res = unlinkat(parent_fobject->fd, name, is_dir ? AT_REMOVEDIR : 0); 1475e21c39aaSAnton Nayshtut if (res) { 1476e21c39aaSAnton Nayshtut res = -errno; 1477e21c39aaSAnton Nayshtut SPDK_WARNLOG("unlinkat(" FOBJECT_FMT " %s) failed (err=%d)\n", 1478e21c39aaSAnton Nayshtut FOBJECT_ARGS(parent_fobject), name, res); 1479e21c39aaSAnton Nayshtut } 1480e21c39aaSAnton Nayshtut 1481e21c39aaSAnton Nayshtut file_object_unref(fobject, 1); 1482e21c39aaSAnton Nayshtut return res; 1483e21c39aaSAnton Nayshtut } 1484e21c39aaSAnton Nayshtut 1485e21c39aaSAnton Nayshtut static int 1486e21c39aaSAnton Nayshtut lo_unlink(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1487e21c39aaSAnton Nayshtut { 1488e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1489e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject = fsdev_io->u_in.unlink.parent_fobject; 1490e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.unlink.name; 1491e21c39aaSAnton Nayshtut 1492e21c39aaSAnton Nayshtut return lo_do_unlink(vfsdev, parent_fobject, name, false); 1493e21c39aaSAnton Nayshtut } 1494e21c39aaSAnton Nayshtut 1495e21c39aaSAnton Nayshtut static int 1496e21c39aaSAnton Nayshtut lo_rmdir(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1497e21c39aaSAnton Nayshtut { 1498e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1499e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject = fsdev_io->u_in.rmdir.parent_fobject; 1500e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.rmdir.name; 1501e21c39aaSAnton Nayshtut 1502e21c39aaSAnton Nayshtut return lo_do_unlink(vfsdev, parent_fobject, name, true); 1503e21c39aaSAnton Nayshtut } 1504e21c39aaSAnton Nayshtut 1505e21c39aaSAnton Nayshtut static int 1506e21c39aaSAnton Nayshtut lo_rename(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1507e21c39aaSAnton Nayshtut { 1508e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1509e21c39aaSAnton Nayshtut int res, saverr; 1510e21c39aaSAnton Nayshtut /* old_fobject must be initialized to avoid a scan-build false positive */ 1511e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *old_fobject = NULL; 1512e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *parent_fobject = fsdev_io->u_in.rename.parent_fobject; 1513e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.rename.name; 1514e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *new_parent_fobject = fsdev_io->u_in.rename.new_parent_fobject; 1515e21c39aaSAnton Nayshtut char *new_name = fsdev_io->u_in.rename.new_name; 1516e21c39aaSAnton Nayshtut uint32_t flags = fsdev_io->u_in.rename.flags; 1517e21c39aaSAnton Nayshtut 1518e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, parent_fobject)) { 1519e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid parent_fobject: %p\n", parent_fobject); 1520e21c39aaSAnton Nayshtut return -EINVAL; 1521e21c39aaSAnton Nayshtut } 1522e21c39aaSAnton Nayshtut 1523e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, new_parent_fobject)) { 1524e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid new_parent_fobject: %p\n", new_parent_fobject); 1525e21c39aaSAnton Nayshtut return -EINVAL; 1526e21c39aaSAnton Nayshtut } 1527e21c39aaSAnton Nayshtut 1528e21c39aaSAnton Nayshtut if (!is_safe_path_component(name)) { 1529e21c39aaSAnton Nayshtut SPDK_ERRLOG("name '%s' isn't safe\n", name); 1530e21c39aaSAnton Nayshtut return -EINVAL; 1531e21c39aaSAnton Nayshtut } 1532e21c39aaSAnton Nayshtut 1533e21c39aaSAnton Nayshtut if (!is_safe_path_component(new_name)) { 1534e21c39aaSAnton Nayshtut SPDK_ERRLOG("newname '%s' isn't safe\n", new_name); 1535e21c39aaSAnton Nayshtut return -EINVAL; 1536e21c39aaSAnton Nayshtut } 1537e21c39aaSAnton Nayshtut 1538e21c39aaSAnton Nayshtut res = lo_do_lookup(vfsdev, parent_fobject, name, &old_fobject, NULL); 1539e21c39aaSAnton Nayshtut if (res) { 1540e21c39aaSAnton Nayshtut SPDK_ERRLOG("can't find '%s' under " FOBJECT_FMT "\n", name, FOBJECT_ARGS(parent_fobject)); 1541e21c39aaSAnton Nayshtut return -EIO; 1542e21c39aaSAnton Nayshtut } 1543e21c39aaSAnton Nayshtut 1544e21c39aaSAnton Nayshtut saverr = 0; 1545e21c39aaSAnton Nayshtut if (flags) { 1546e21c39aaSAnton Nayshtut #ifndef SYS_renameat2 1547e21c39aaSAnton Nayshtut SPDK_ERRLOG("flags are not supported\n"); 1548e21c39aaSAnton Nayshtut return -ENOTSUP; 1549e21c39aaSAnton Nayshtut #else 1550e21c39aaSAnton Nayshtut res = syscall(SYS_renameat2, parent_fobject->fd, name, new_parent_fobject->fd, 1551e21c39aaSAnton Nayshtut new_name, flags); 1552e21c39aaSAnton Nayshtut if (res == -1 && errno == ENOSYS) { 1553e21c39aaSAnton Nayshtut SPDK_ERRLOG("SYS_renameat2 returned ENOSYS\n"); 1554e21c39aaSAnton Nayshtut saverr = -EINVAL; 1555e21c39aaSAnton Nayshtut } else if (res == -1) { 1556e21c39aaSAnton Nayshtut saverr = -errno; 1557e21c39aaSAnton Nayshtut SPDK_ERRLOG("SYS_renameat2 failed (err=%d))\n", saverr); 1558e21c39aaSAnton Nayshtut } 1559e21c39aaSAnton Nayshtut #endif 1560e21c39aaSAnton Nayshtut } else { 1561e21c39aaSAnton Nayshtut res = renameat(parent_fobject->fd, name, new_parent_fobject->fd, new_name); 1562e21c39aaSAnton Nayshtut if (res == -1) { 1563e21c39aaSAnton Nayshtut saverr = -errno; 1564e21c39aaSAnton Nayshtut SPDK_ERRLOG("renameat failed (err=%d)\n", saverr); 1565e21c39aaSAnton Nayshtut } 1566e21c39aaSAnton Nayshtut } 1567e21c39aaSAnton Nayshtut 1568e21c39aaSAnton Nayshtut file_object_unref(old_fobject, 1); 1569e21c39aaSAnton Nayshtut 1570e21c39aaSAnton Nayshtut return saverr; 1571e21c39aaSAnton Nayshtut } 1572e21c39aaSAnton Nayshtut 1573e21c39aaSAnton Nayshtut static int 1574e21c39aaSAnton Nayshtut linkat_empty_nofollow(struct aio_fsdev *vfsdev, struct spdk_fsdev_file_object *fobject, int dfd, 1575e21c39aaSAnton Nayshtut const char *name) 1576e21c39aaSAnton Nayshtut { 1577e21c39aaSAnton Nayshtut int res; 1578e21c39aaSAnton Nayshtut 1579e21c39aaSAnton Nayshtut if (fobject->is_symlink) { 1580e21c39aaSAnton Nayshtut res = linkat(fobject->fd, "", dfd, name, AT_EMPTY_PATH); 1581e21c39aaSAnton Nayshtut if (res == -1 && (errno == ENOENT || errno == EINVAL)) { 1582e21c39aaSAnton Nayshtut /* Sorry, no race free way to hard-link a symlink. */ 1583e21c39aaSAnton Nayshtut errno = EPERM; 1584e21c39aaSAnton Nayshtut } 1585e21c39aaSAnton Nayshtut } else { 1586e21c39aaSAnton Nayshtut res = linkat(vfsdev->proc_self_fd, fobject->fd_str, dfd, name, AT_SYMLINK_FOLLOW); 1587e21c39aaSAnton Nayshtut } 1588e21c39aaSAnton Nayshtut 1589e21c39aaSAnton Nayshtut return res; 1590e21c39aaSAnton Nayshtut } 1591e21c39aaSAnton Nayshtut 1592e21c39aaSAnton Nayshtut static int 1593e21c39aaSAnton Nayshtut lo_link(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1594e21c39aaSAnton Nayshtut { 1595e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1596e21c39aaSAnton Nayshtut int res; 1597e21c39aaSAnton Nayshtut int saverr; 1598e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.link.fobject; 1599e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *new_parent_fobject = fsdev_io->u_in.link.new_parent_fobject; 1600e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.link.name; 1601e21c39aaSAnton Nayshtut 1602e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1603e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1604e21c39aaSAnton Nayshtut return -EINVAL; 1605e21c39aaSAnton Nayshtut } 1606e21c39aaSAnton Nayshtut 1607e21c39aaSAnton Nayshtut if (!is_safe_path_component(name)) { 1608e21c39aaSAnton Nayshtut SPDK_ERRLOG("%s is not a safe component\n", name); 1609e21c39aaSAnton Nayshtut return -EINVAL; 1610e21c39aaSAnton Nayshtut } 1611e21c39aaSAnton Nayshtut 1612e21c39aaSAnton Nayshtut res = linkat_empty_nofollow(vfsdev, fobject, new_parent_fobject->fd, name); 1613e21c39aaSAnton Nayshtut if (res == -1) { 1614e21c39aaSAnton Nayshtut saverr = -errno; 1615e21c39aaSAnton Nayshtut SPDK_ERRLOG("linkat_empty_nofollow failed " FOBJECT_FMT " -> " FOBJECT_FMT " name=%s (err=%d)\n", 1616e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), FOBJECT_ARGS(new_parent_fobject), name, saverr); 1617e21c39aaSAnton Nayshtut return saverr; 1618e21c39aaSAnton Nayshtut } 1619e21c39aaSAnton Nayshtut 1620e21c39aaSAnton Nayshtut res = lo_do_lookup(vfsdev, new_parent_fobject, name, &fsdev_io->u_out.link.fobject, 1621e21c39aaSAnton Nayshtut &fsdev_io->u_out.link.attr); 1622e21c39aaSAnton Nayshtut if (res) { 1623e21c39aaSAnton Nayshtut SPDK_ERRLOG("lookup failed (err=%d)\n", res); 1624e21c39aaSAnton Nayshtut return res; 1625e21c39aaSAnton Nayshtut } 1626e21c39aaSAnton Nayshtut 1627e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "LINK succeeded for " FOBJECT_FMT " -> " FOBJECT_FMT " name=%s\n", 1628e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), FOBJECT_ARGS(fsdev_io->u_out.link.fobject), name); 1629e21c39aaSAnton Nayshtut 1630e21c39aaSAnton Nayshtut return 0; 1631e21c39aaSAnton Nayshtut } 1632e21c39aaSAnton Nayshtut 1633e21c39aaSAnton Nayshtut static int 1634e21c39aaSAnton Nayshtut lo_fsync(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1635e21c39aaSAnton Nayshtut { 1636e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1637e21c39aaSAnton Nayshtut int res, saverr, fd; 1638e21c39aaSAnton Nayshtut char *buf; 1639e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.fsync.fobject; 1640e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.fsync.fhandle; 1641e21c39aaSAnton Nayshtut bool datasync = fsdev_io->u_in.fsync.datasync; 1642e21c39aaSAnton Nayshtut 1643e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1644e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1645e21c39aaSAnton Nayshtut return -EINVAL; 1646e21c39aaSAnton Nayshtut } 1647e21c39aaSAnton Nayshtut 1648e21c39aaSAnton Nayshtut if (!fhandle) { 1649e21c39aaSAnton Nayshtut res = asprintf(&buf, "%i", fobject->fd); 1650e21c39aaSAnton Nayshtut if (res == -1) { 1651e21c39aaSAnton Nayshtut saverr = -errno; 1652e21c39aaSAnton Nayshtut SPDK_ERRLOG("asprintf failed (errno=%d)\n", saverr); 1653e21c39aaSAnton Nayshtut return saverr; 1654e21c39aaSAnton Nayshtut } 1655e21c39aaSAnton Nayshtut 1656e21c39aaSAnton Nayshtut fd = openat(vfsdev->proc_self_fd, buf, O_RDWR); 1657e21c39aaSAnton Nayshtut saverr = -errno; 1658e21c39aaSAnton Nayshtut free(buf); 1659e21c39aaSAnton Nayshtut if (fd == -1) { 1660e21c39aaSAnton Nayshtut SPDK_ERRLOG("openat failed (errno=%d)\n", saverr); 1661e21c39aaSAnton Nayshtut return saverr; 1662e21c39aaSAnton Nayshtut } 1663e21c39aaSAnton Nayshtut } else { 1664e21c39aaSAnton Nayshtut fd = fhandle->fd; 1665e21c39aaSAnton Nayshtut } 1666e21c39aaSAnton Nayshtut 1667e21c39aaSAnton Nayshtut if (datasync) { 1668e21c39aaSAnton Nayshtut res = fdatasync(fd); 1669e21c39aaSAnton Nayshtut } else { 1670e21c39aaSAnton Nayshtut res = fsync(fd); 1671e21c39aaSAnton Nayshtut } 1672e21c39aaSAnton Nayshtut 1673e21c39aaSAnton Nayshtut saverr = -errno; 1674e21c39aaSAnton Nayshtut if (!fhandle) { 1675e21c39aaSAnton Nayshtut close(fd); 1676e21c39aaSAnton Nayshtut } 1677e21c39aaSAnton Nayshtut 1678e21c39aaSAnton Nayshtut if (res == -1) { 1679e21c39aaSAnton Nayshtut SPDK_ERRLOG("fdatasync/fsync failed for " FOBJECT_FMT " fh=%p (err=%d)\n", 1680e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), fhandle, saverr); 1681e21c39aaSAnton Nayshtut return saverr; 1682e21c39aaSAnton Nayshtut } 1683e21c39aaSAnton Nayshtut 1684e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "FSYNC succeeded for " FOBJECT_FMT " fh=%p\n", 1685e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), fhandle); 1686e21c39aaSAnton Nayshtut 1687e21c39aaSAnton Nayshtut return 0; 1688e21c39aaSAnton Nayshtut } 1689e21c39aaSAnton Nayshtut 1690e21c39aaSAnton Nayshtut static int 1691e21c39aaSAnton Nayshtut lo_setxattr(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1692e21c39aaSAnton Nayshtut { 1693e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1694e21c39aaSAnton Nayshtut ssize_t ret; 1695e21c39aaSAnton Nayshtut int saverr; 1696e21c39aaSAnton Nayshtut int fd = -1; 1697e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.setxattr.fobject; 1698e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.setxattr.name; 1699e21c39aaSAnton Nayshtut char *value = fsdev_io->u_in.setxattr.value; 1700e21c39aaSAnton Nayshtut uint32_t size = fsdev_io->u_in.setxattr.size; 1701e21c39aaSAnton Nayshtut uint32_t flags = fsdev_io->u_in.setxattr.flags; 1702e21c39aaSAnton Nayshtut 1703e21c39aaSAnton Nayshtut if (!vfsdev->xattr_enabled) { 1704e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "xattr is disabled by config\n"); 1705e21c39aaSAnton Nayshtut return -ENOSYS; 1706e21c39aaSAnton Nayshtut } 1707e21c39aaSAnton Nayshtut 1708e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1709e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1710e21c39aaSAnton Nayshtut return -EINVAL; 1711e21c39aaSAnton Nayshtut } 1712e21c39aaSAnton Nayshtut 1713e21c39aaSAnton Nayshtut if (fobject->is_symlink) { 1714e21c39aaSAnton Nayshtut /* Sorry, no race free way to removexattr on symlink. */ 1715e21c39aaSAnton Nayshtut SPDK_ERRLOG("cannot set xattr for symlink\n"); 1716e21c39aaSAnton Nayshtut return -EPERM; 1717e21c39aaSAnton Nayshtut } 1718e21c39aaSAnton Nayshtut 1719e21c39aaSAnton Nayshtut fd = openat(vfsdev->proc_self_fd, fobject->fd_str, O_RDWR); 1720e21c39aaSAnton Nayshtut if (fd < 0) { 1721e21c39aaSAnton Nayshtut saverr = -errno; 1722e21c39aaSAnton Nayshtut SPDK_ERRLOG("openat failed with errno=%d\n", saverr); 1723e21c39aaSAnton Nayshtut return saverr; 1724e21c39aaSAnton Nayshtut } 1725e21c39aaSAnton Nayshtut 1726e21c39aaSAnton Nayshtut ret = fsetxattr(fd, name, value, size, flags); 1727e21c39aaSAnton Nayshtut saverr = -errno; 1728e21c39aaSAnton Nayshtut close(fd); 1729e21c39aaSAnton Nayshtut if (ret == -1) { 1730e21c39aaSAnton Nayshtut if (saverr == -ENOTSUP) { 1731e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "flistxattr: extended attributes are not supported or disabled\n"); 1732e21c39aaSAnton Nayshtut } else { 1733e21c39aaSAnton Nayshtut SPDK_ERRLOG("flistxattr failed with errno=%d\n", saverr); 1734e21c39aaSAnton Nayshtut } 1735e21c39aaSAnton Nayshtut return saverr; 1736e21c39aaSAnton Nayshtut } 1737e21c39aaSAnton Nayshtut 1738e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, 1739e21c39aaSAnton Nayshtut "SETXATTR succeeded for " FOBJECT_FMT " name=%s value=%s size=%" PRIu32 "flags=0x%x" PRIx32 "\n", 1740e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), name, value, size, flags); 1741e21c39aaSAnton Nayshtut 1742e21c39aaSAnton Nayshtut return 0; 1743e21c39aaSAnton Nayshtut } 1744e21c39aaSAnton Nayshtut 1745e21c39aaSAnton Nayshtut static int 1746e21c39aaSAnton Nayshtut lo_getxattr(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1747e21c39aaSAnton Nayshtut { 1748e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1749e21c39aaSAnton Nayshtut ssize_t ret; 1750e21c39aaSAnton Nayshtut int saverr; 1751e21c39aaSAnton Nayshtut int fd = -1; 1752e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.getxattr.fobject; 1753e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.getxattr.name; 1754e21c39aaSAnton Nayshtut void *buffer = fsdev_io->u_in.getxattr.buffer; 1755e21c39aaSAnton Nayshtut size_t size = fsdev_io->u_in.getxattr.size; 1756e21c39aaSAnton Nayshtut 1757e21c39aaSAnton Nayshtut if (!vfsdev->xattr_enabled) { 1758e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "xattr is disabled by config\n"); 1759e21c39aaSAnton Nayshtut return -ENOSYS; 1760e21c39aaSAnton Nayshtut } 1761e21c39aaSAnton Nayshtut 1762e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1763e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1764e21c39aaSAnton Nayshtut return -EINVAL; 1765e21c39aaSAnton Nayshtut } 1766e21c39aaSAnton Nayshtut 1767e21c39aaSAnton Nayshtut if (fobject->is_symlink) { 1768e21c39aaSAnton Nayshtut /* Sorry, no race free way to getxattr on symlink. */ 1769e21c39aaSAnton Nayshtut SPDK_ERRLOG("cannot get xattr for symlink\n"); 1770e21c39aaSAnton Nayshtut return -EPERM; 1771e21c39aaSAnton Nayshtut } 1772e21c39aaSAnton Nayshtut 1773e21c39aaSAnton Nayshtut fd = openat(vfsdev->proc_self_fd, fobject->fd_str, O_RDWR); 1774e21c39aaSAnton Nayshtut if (fd < 0) { 1775e21c39aaSAnton Nayshtut saverr = -errno; 1776e21c39aaSAnton Nayshtut SPDK_ERRLOG("openat failed with errno=%d\n", saverr); 1777e21c39aaSAnton Nayshtut return saverr; 1778e21c39aaSAnton Nayshtut } 1779e21c39aaSAnton Nayshtut 1780e21c39aaSAnton Nayshtut ret = fgetxattr(fd, name, buffer, size); 1781e21c39aaSAnton Nayshtut saverr = -errno; 1782e21c39aaSAnton Nayshtut close(fd); 1783e21c39aaSAnton Nayshtut if (ret == -1) { 1784e21c39aaSAnton Nayshtut if (saverr == -ENODATA) { 1785e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "fgetxattr: no extended attribute '%s' found\n", name); 1786e21c39aaSAnton Nayshtut } else if (saverr == -ENOTSUP) { 1787e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "fgetxattr: extended attributes are not supported or disabled\n"); 1788e21c39aaSAnton Nayshtut } else { 1789e21c39aaSAnton Nayshtut SPDK_ERRLOG("fgetxattr failed with errno=%d\n", saverr); 1790e21c39aaSAnton Nayshtut } 1791e21c39aaSAnton Nayshtut return saverr; 1792e21c39aaSAnton Nayshtut } 1793e21c39aaSAnton Nayshtut 1794e21c39aaSAnton Nayshtut fsdev_io->u_out.getxattr.value_size = ret; 1795e21c39aaSAnton Nayshtut 1796e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, 1797e21c39aaSAnton Nayshtut "GETXATTR succeeded for " FOBJECT_FMT " name=%s value=%s value_size=%zd\n", 1798e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), name, (char *)buffer, ret); 1799e21c39aaSAnton Nayshtut 1800e21c39aaSAnton Nayshtut return 0; 1801e21c39aaSAnton Nayshtut } 1802e21c39aaSAnton Nayshtut 1803e21c39aaSAnton Nayshtut static int 1804e21c39aaSAnton Nayshtut lo_listxattr(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1805e21c39aaSAnton Nayshtut { 1806e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1807e21c39aaSAnton Nayshtut ssize_t ret; 1808e21c39aaSAnton Nayshtut int saverr; 1809e21c39aaSAnton Nayshtut int fd = -1; 1810e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.listxattr.fobject; 1811e21c39aaSAnton Nayshtut char *buffer = fsdev_io->u_in.listxattr.buffer; 1812e21c39aaSAnton Nayshtut size_t size = fsdev_io->u_in.listxattr.size; 1813e21c39aaSAnton Nayshtut 1814e21c39aaSAnton Nayshtut if (!vfsdev->xattr_enabled) { 1815e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "xattr is disabled by config\n"); 1816e21c39aaSAnton Nayshtut return -ENOSYS; 1817e21c39aaSAnton Nayshtut } 1818e21c39aaSAnton Nayshtut 1819e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1820e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1821e21c39aaSAnton Nayshtut return -EINVAL; 1822e21c39aaSAnton Nayshtut } 1823e21c39aaSAnton Nayshtut 1824e21c39aaSAnton Nayshtut if (fobject->is_symlink) { 1825e21c39aaSAnton Nayshtut /* Sorry, no race free way to listxattr on symlink. */ 1826e21c39aaSAnton Nayshtut SPDK_ERRLOG("cannot list xattr for symlink\n"); 1827e21c39aaSAnton Nayshtut return -EPERM; 1828e21c39aaSAnton Nayshtut } 1829e21c39aaSAnton Nayshtut 1830e21c39aaSAnton Nayshtut fd = openat(vfsdev->proc_self_fd, fobject->fd_str, O_RDONLY); 1831e21c39aaSAnton Nayshtut if (fd < 0) { 1832e21c39aaSAnton Nayshtut saverr = -errno; 1833e21c39aaSAnton Nayshtut SPDK_ERRLOG("openat failed with errno=%d\n", saverr); 1834e21c39aaSAnton Nayshtut return saverr; 1835e21c39aaSAnton Nayshtut } 1836e21c39aaSAnton Nayshtut 1837e21c39aaSAnton Nayshtut ret = flistxattr(fd, buffer, size); 1838e21c39aaSAnton Nayshtut saverr = -errno; 1839e21c39aaSAnton Nayshtut close(fd); 1840e21c39aaSAnton Nayshtut if (ret == -1) { 1841e21c39aaSAnton Nayshtut if (saverr == -ENOTSUP) { 1842e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "flistxattr: extended attributes are not supported or disabled\n"); 1843e21c39aaSAnton Nayshtut } else { 1844e21c39aaSAnton Nayshtut SPDK_ERRLOG("flistxattr failed with errno=%d\n", saverr); 1845e21c39aaSAnton Nayshtut } 1846e21c39aaSAnton Nayshtut return saverr; 1847e21c39aaSAnton Nayshtut } 1848e21c39aaSAnton Nayshtut 1849e21c39aaSAnton Nayshtut fsdev_io->u_out.listxattr.data_size = ret; 1850e21c39aaSAnton Nayshtut fsdev_io->u_out.listxattr.size_only = (size == 0); 1851e21c39aaSAnton Nayshtut 1852e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "LISTXATTR succeeded for " FOBJECT_FMT " data_size=%zu\n", 1853e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), ret); 1854e21c39aaSAnton Nayshtut 1855e21c39aaSAnton Nayshtut return 0; 1856e21c39aaSAnton Nayshtut } 1857e21c39aaSAnton Nayshtut 1858e21c39aaSAnton Nayshtut static int 1859e21c39aaSAnton Nayshtut lo_removexattr(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1860e21c39aaSAnton Nayshtut { 1861e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1862e21c39aaSAnton Nayshtut ssize_t ret; 1863e21c39aaSAnton Nayshtut int saverr; 1864e21c39aaSAnton Nayshtut int fd = -1; 1865e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.removexattr.fobject; 1866e21c39aaSAnton Nayshtut char *name = fsdev_io->u_in.removexattr.name; 1867e21c39aaSAnton Nayshtut 1868e21c39aaSAnton Nayshtut if (!vfsdev->xattr_enabled) { 1869e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "xattr is disabled by config\n"); 1870e21c39aaSAnton Nayshtut return -ENOSYS; 1871e21c39aaSAnton Nayshtut } 1872e21c39aaSAnton Nayshtut 1873e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1874e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1875e21c39aaSAnton Nayshtut return -EINVAL; 1876e21c39aaSAnton Nayshtut } 1877e21c39aaSAnton Nayshtut 1878e21c39aaSAnton Nayshtut if (fobject->is_symlink) { 1879e21c39aaSAnton Nayshtut /* Sorry, no race free way to setxattr on symlink. */ 1880e21c39aaSAnton Nayshtut SPDK_ERRLOG("cannot list xattr for symlink\n"); 1881e21c39aaSAnton Nayshtut return -EPERM; 1882e21c39aaSAnton Nayshtut } 1883e21c39aaSAnton Nayshtut 1884e21c39aaSAnton Nayshtut fd = openat(vfsdev->proc_self_fd, fobject->fd_str, O_RDONLY); 1885e21c39aaSAnton Nayshtut if (fd < 0) { 1886e21c39aaSAnton Nayshtut saverr = -errno; 1887e21c39aaSAnton Nayshtut SPDK_ERRLOG("openat failed with errno=%d\n", saverr); 1888e21c39aaSAnton Nayshtut return saverr; 1889e21c39aaSAnton Nayshtut } 1890e21c39aaSAnton Nayshtut 1891e21c39aaSAnton Nayshtut ret = fremovexattr(fd, name); 1892e21c39aaSAnton Nayshtut saverr = -errno; 1893e21c39aaSAnton Nayshtut close(fd); 1894e21c39aaSAnton Nayshtut if (ret == -1) { 1895e21c39aaSAnton Nayshtut if (saverr == -ENODATA) { 1896e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "fremovexattr: no extended attribute '%s' found\n", name); 1897e21c39aaSAnton Nayshtut } else if (saverr == -ENOTSUP) { 1898e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "fremovexattr: extended attributes are not supported or disabled\n"); 1899e21c39aaSAnton Nayshtut } else { 1900e21c39aaSAnton Nayshtut SPDK_ERRLOG("fremovexattr failed with errno=%d\n", saverr); 1901e21c39aaSAnton Nayshtut } 1902e21c39aaSAnton Nayshtut return saverr; 1903e21c39aaSAnton Nayshtut } 1904e21c39aaSAnton Nayshtut 1905e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "REMOVEXATTR succeeded for " FOBJECT_FMT " name=%s\n", 1906e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), name); 1907e21c39aaSAnton Nayshtut 1908e21c39aaSAnton Nayshtut return 0; 1909e21c39aaSAnton Nayshtut } 1910e21c39aaSAnton Nayshtut 1911e21c39aaSAnton Nayshtut static int 1912e21c39aaSAnton Nayshtut lo_fsyncdir(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1913e21c39aaSAnton Nayshtut { 1914e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1915e21c39aaSAnton Nayshtut int res; 1916e21c39aaSAnton Nayshtut int saverr = 0; 1917e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.fsyncdir.fobject; 1918e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.fsyncdir.fhandle; 1919e21c39aaSAnton Nayshtut bool datasync = fsdev_io->u_in.fsyncdir.datasync; 1920e21c39aaSAnton Nayshtut 1921e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1922e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1923e21c39aaSAnton Nayshtut return -EINVAL; 1924e21c39aaSAnton Nayshtut } 1925e21c39aaSAnton Nayshtut 1926e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle)) { 1927e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle: %p\n", fhandle); 1928e21c39aaSAnton Nayshtut return -EINVAL; 1929e21c39aaSAnton Nayshtut } 1930e21c39aaSAnton Nayshtut 1931e21c39aaSAnton Nayshtut if (datasync) { 1932e21c39aaSAnton Nayshtut res = fdatasync(fhandle->fd); 1933e21c39aaSAnton Nayshtut } else { 1934e21c39aaSAnton Nayshtut res = fsync(fhandle->fd); 1935e21c39aaSAnton Nayshtut } 1936e21c39aaSAnton Nayshtut 1937e21c39aaSAnton Nayshtut if (res == -1) { 1938e21c39aaSAnton Nayshtut saverr = -errno; 1939e21c39aaSAnton Nayshtut SPDK_ERRLOG("%s failed for fh=%p with err=%d\n", 1940e21c39aaSAnton Nayshtut datasync ? "fdatasync" : "fsync", fhandle, saverr); 1941e21c39aaSAnton Nayshtut return saverr; 1942e21c39aaSAnton Nayshtut } 1943e21c39aaSAnton Nayshtut 1944e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "FSYNCDIR succeeded for " FOBJECT_FMT " fh=%p datasync=%d\n", 1945e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), fhandle, datasync); 1946e21c39aaSAnton Nayshtut 1947e21c39aaSAnton Nayshtut return 0; 1948e21c39aaSAnton Nayshtut } 1949e21c39aaSAnton Nayshtut 1950e21c39aaSAnton Nayshtut static int 1951e21c39aaSAnton Nayshtut lo_flock(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1952e21c39aaSAnton Nayshtut { 1953e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1954e21c39aaSAnton Nayshtut int res; 1955e21c39aaSAnton Nayshtut int saverr = 0; 1956e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.flock.fobject; 1957e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.flock.fhandle; 1958e21c39aaSAnton Nayshtut int operation = fsdev_io->u_in.flock.operation; 1959e21c39aaSAnton Nayshtut 1960e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1961e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1962e21c39aaSAnton Nayshtut return -EINVAL; 1963e21c39aaSAnton Nayshtut } 1964e21c39aaSAnton Nayshtut 1965e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle)) { 1966e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle: %p\n", fhandle); 1967e21c39aaSAnton Nayshtut return -EINVAL; 1968e21c39aaSAnton Nayshtut } 1969e21c39aaSAnton Nayshtut 1970e21c39aaSAnton Nayshtut res = flock(fhandle->fd, operation | LOCK_NB); 1971e21c39aaSAnton Nayshtut if (res == -1) { 1972e21c39aaSAnton Nayshtut saverr = -errno; 1973e21c39aaSAnton Nayshtut SPDK_ERRLOG("flock failed for fh=%p with err=%d\n", fhandle, saverr); 1974e21c39aaSAnton Nayshtut return saverr; 1975e21c39aaSAnton Nayshtut } 1976e21c39aaSAnton Nayshtut 1977e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "FLOCK succeeded for " FOBJECT_FMT " fh=%p operation=%d\n", 1978e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject), fhandle, operation); 1979e21c39aaSAnton Nayshtut 1980e21c39aaSAnton Nayshtut return 0; 1981e21c39aaSAnton Nayshtut } 1982e21c39aaSAnton Nayshtut 1983e21c39aaSAnton Nayshtut static int 1984e21c39aaSAnton Nayshtut lo_fallocate(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 1985e21c39aaSAnton Nayshtut { 1986e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 1987e21c39aaSAnton Nayshtut int err; 1988e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject = fsdev_io->u_in.fallocate.fobject; 1989e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle = fsdev_io->u_in.fallocate.fhandle; 1990e21c39aaSAnton Nayshtut uint32_t mode = fsdev_io->u_in.fallocate.mode; 1991e21c39aaSAnton Nayshtut uint64_t offset = fsdev_io->u_in.fallocate.offset; 1992e21c39aaSAnton Nayshtut uint64_t length = fsdev_io->u_in.fallocate.length; 1993e21c39aaSAnton Nayshtut 1994e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject)) { 1995e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject: %p\n", fobject); 1996e21c39aaSAnton Nayshtut return -EINVAL; 1997e21c39aaSAnton Nayshtut } 1998e21c39aaSAnton Nayshtut 1999e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle)) { 2000e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle: %p\n", fhandle); 2001e21c39aaSAnton Nayshtut return -EINVAL; 2002e21c39aaSAnton Nayshtut } 2003e21c39aaSAnton Nayshtut 2004e21c39aaSAnton Nayshtut if (mode) { 2005e21c39aaSAnton Nayshtut SPDK_ERRLOG("non-zero mode is not suppored\n"); 2006e21c39aaSAnton Nayshtut return -EOPNOTSUPP; 2007e21c39aaSAnton Nayshtut } 2008e21c39aaSAnton Nayshtut 2009e21c39aaSAnton Nayshtut err = posix_fallocate(fhandle->fd, offset, length); 2010e21c39aaSAnton Nayshtut if (err) { 2011e21c39aaSAnton Nayshtut SPDK_ERRLOG("posix_fallocate failed for fh=%p with err=%d\n", 2012e21c39aaSAnton Nayshtut fhandle, err); 2013e21c39aaSAnton Nayshtut } 2014e21c39aaSAnton Nayshtut 2015e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, 2016e21c39aaSAnton Nayshtut "FALLOCATE returns %d for " FOBJECT_FMT " fh=%p offset=%" PRIu64 " length=%" PRIu64 "\n", 2017e21c39aaSAnton Nayshtut err, FOBJECT_ARGS(fobject), fhandle, offset, length); 2018e21c39aaSAnton Nayshtut return err; 2019e21c39aaSAnton Nayshtut } 2020e21c39aaSAnton Nayshtut 2021e21c39aaSAnton Nayshtut static int 2022e21c39aaSAnton Nayshtut lo_copy_file_range(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 2023e21c39aaSAnton Nayshtut { 2024e21c39aaSAnton Nayshtut #ifdef SPDK_CONFIG_COPY_FILE_RANGE 2025e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev_io->fsdev); 2026e21c39aaSAnton Nayshtut ssize_t res; 2027e21c39aaSAnton Nayshtut int saverr = 0; 2028e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject_in = fsdev_io->u_in.copy_file_range.fobject_in; 2029e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle_in = fsdev_io->u_in.copy_file_range.fhandle_in; 2030e21c39aaSAnton Nayshtut off_t off_in = fsdev_io->u_in.copy_file_range.off_in; 2031e21c39aaSAnton Nayshtut struct spdk_fsdev_file_object *fobject_out = fsdev_io->u_in.copy_file_range.fobject_out; 2032e21c39aaSAnton Nayshtut struct spdk_fsdev_file_handle *fhandle_out = fsdev_io->u_in.copy_file_range.fhandle_out; 2033e21c39aaSAnton Nayshtut off_t off_out = fsdev_io->u_in.copy_file_range.off_out; 2034e21c39aaSAnton Nayshtut size_t len = fsdev_io->u_in.copy_file_range.len; 2035e21c39aaSAnton Nayshtut uint32_t flags = fsdev_io->u_in.copy_file_range.flags; 2036e21c39aaSAnton Nayshtut 2037e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject_in)) { 2038e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject_in: %p\n", fobject_in); 2039e21c39aaSAnton Nayshtut return -EINVAL; 2040e21c39aaSAnton Nayshtut } 2041e21c39aaSAnton Nayshtut 2042e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle_in)) { 2043e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle_in: %p\n", fhandle_in); 2044e21c39aaSAnton Nayshtut return -EINVAL; 2045e21c39aaSAnton Nayshtut } 2046e21c39aaSAnton Nayshtut 2047e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fobject(vfsdev, fobject_out)) { 2048e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fobject_out: %p\n", fobject_out); 2049e21c39aaSAnton Nayshtut return -EINVAL; 2050e21c39aaSAnton Nayshtut } 2051e21c39aaSAnton Nayshtut 2052e21c39aaSAnton Nayshtut if (!fsdev_aio_is_valid_fhandle(vfsdev, fhandle_out)) { 2053e21c39aaSAnton Nayshtut SPDK_ERRLOG("Invalid fhandle_out: %p\n", fhandle_out); 2054e21c39aaSAnton Nayshtut return -EINVAL; 2055e21c39aaSAnton Nayshtut } 2056e21c39aaSAnton Nayshtut 2057e21c39aaSAnton Nayshtut res = copy_file_range(fhandle_in->fd, &off_in, fhandle_out->fd, &off_out, len, flags); 2058e21c39aaSAnton Nayshtut if (res < 0) { 2059e21c39aaSAnton Nayshtut saverr = -errno; 2060e21c39aaSAnton Nayshtut SPDK_ERRLOG("copy_file_range failed with err=%d\n", saverr); 2061e21c39aaSAnton Nayshtut return saverr; 2062e21c39aaSAnton Nayshtut } 2063e21c39aaSAnton Nayshtut 2064e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, 2065e21c39aaSAnton Nayshtut "COPY_FILE_RANGE succeeded for " FOBJECT_FMT " fh=%p offset=%" PRIu64 " -> " FOBJECT_FMT 2066e21c39aaSAnton Nayshtut " fh=%p offset=%" PRIu64 " (len-%zu flags=0x%" PRIx32 ")\n", 2067e21c39aaSAnton Nayshtut FOBJECT_ARGS(fobject_in), fhandle_in, (uint64_t)off_in, FOBJECT_ARGS(fobject_out), fhandle_out, 2068e21c39aaSAnton Nayshtut (uint64_t)off_out, len, flags); 2069e21c39aaSAnton Nayshtut 2070e21c39aaSAnton Nayshtut return 0; 2071e21c39aaSAnton Nayshtut #else 2072e21c39aaSAnton Nayshtut return -ENOSYS; 2073e21c39aaSAnton Nayshtut #endif 2074e21c39aaSAnton Nayshtut } 2075e21c39aaSAnton Nayshtut 2076e21c39aaSAnton Nayshtut static int 2077e21c39aaSAnton Nayshtut lo_abort(struct spdk_io_channel *_ch, struct spdk_fsdev_io *fsdev_io) 2078e21c39aaSAnton Nayshtut { 2079e21c39aaSAnton Nayshtut struct aio_io_channel *ch = spdk_io_channel_get_ctx(_ch); 2080e21c39aaSAnton Nayshtut struct aio_fsdev_io *vfsdev_io; 2081e21c39aaSAnton Nayshtut uint64_t unique_to_abort = fsdev_io->u_in.abort.unique_to_abort; 2082e21c39aaSAnton Nayshtut 2083e21c39aaSAnton Nayshtut TAILQ_FOREACH(vfsdev_io, &ch->ios_in_progress, link) { 2084e21c39aaSAnton Nayshtut struct spdk_fsdev_io *_fsdev_io = aio_to_fsdev_io(vfsdev_io); 2085e21c39aaSAnton Nayshtut if (spdk_fsdev_io_get_unique(_fsdev_io) == unique_to_abort) { 2086e21c39aaSAnton Nayshtut spdk_aio_mgr_cancel(ch->mgr, vfsdev_io->aio); 2087e21c39aaSAnton Nayshtut return 0; 2088e21c39aaSAnton Nayshtut } 2089e21c39aaSAnton Nayshtut } 2090e21c39aaSAnton Nayshtut 2091e21c39aaSAnton Nayshtut return 0; 2092e21c39aaSAnton Nayshtut } 2093e21c39aaSAnton Nayshtut 2094e21c39aaSAnton Nayshtut static int 2095e21c39aaSAnton Nayshtut aio_io_poll(void *arg) 2096e21c39aaSAnton Nayshtut { 209792108e0aSYoray Zack struct aio_fsdev_io *vfsdev_io, *tmp; 2098e21c39aaSAnton Nayshtut struct aio_io_channel *ch = arg; 2099a29d7fdfSAnton Nayshtut int res = SPDK_POLLER_IDLE; 2100e21c39aaSAnton Nayshtut 2101a29d7fdfSAnton Nayshtut if (spdk_aio_mgr_poll(ch->mgr)) { 2102a29d7fdfSAnton Nayshtut res = SPDK_POLLER_BUSY; 2103a29d7fdfSAnton Nayshtut } 2104e21c39aaSAnton Nayshtut 210592108e0aSYoray Zack TAILQ_FOREACH_SAFE(vfsdev_io, &ch->ios_to_complete, link, tmp) { 210692108e0aSYoray Zack struct spdk_fsdev_io *fsdev_io = aio_to_fsdev_io(vfsdev_io); 210792108e0aSYoray Zack 210892108e0aSYoray Zack TAILQ_REMOVE(&ch->ios_to_complete, vfsdev_io, link); 210992108e0aSYoray Zack spdk_fsdev_io_complete(fsdev_io, 0); 2110a29d7fdfSAnton Nayshtut res = SPDK_POLLER_BUSY; 211192108e0aSYoray Zack } 211292108e0aSYoray Zack 2113a29d7fdfSAnton Nayshtut return res; 2114e21c39aaSAnton Nayshtut } 2115e21c39aaSAnton Nayshtut 2116e21c39aaSAnton Nayshtut static int 2117e21c39aaSAnton Nayshtut aio_fsdev_create_cb(void *io_device, void *ctx_buf) 2118e21c39aaSAnton Nayshtut { 2119e21c39aaSAnton Nayshtut struct aio_io_channel *ch = ctx_buf; 2120e21c39aaSAnton Nayshtut struct spdk_thread *thread = spdk_get_thread(); 2121e21c39aaSAnton Nayshtut 2122e21c39aaSAnton Nayshtut ch->mgr = spdk_aio_mgr_create(MAX_AIOS); 2123e21c39aaSAnton Nayshtut if (!ch->mgr) { 2124e21c39aaSAnton Nayshtut SPDK_ERRLOG("aoi manager init for failed (thread=%s)\n", spdk_thread_get_name(thread)); 2125e21c39aaSAnton Nayshtut return -ENOMEM; 2126e21c39aaSAnton Nayshtut } 2127e21c39aaSAnton Nayshtut 2128e21c39aaSAnton Nayshtut ch->poller = SPDK_POLLER_REGISTER(aio_io_poll, ch, 0); 2129e21c39aaSAnton Nayshtut TAILQ_INIT(&ch->ios_in_progress); 213092108e0aSYoray Zack TAILQ_INIT(&ch->ios_to_complete); 2131e21c39aaSAnton Nayshtut 2132e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "Created aio fsdev IO channel: thread %s, thread id %" PRIu64 2133e21c39aaSAnton Nayshtut "\n", 2134e21c39aaSAnton Nayshtut spdk_thread_get_name(thread), spdk_thread_get_id(thread)); 2135e21c39aaSAnton Nayshtut return 0; 2136e21c39aaSAnton Nayshtut } 2137e21c39aaSAnton Nayshtut 2138e21c39aaSAnton Nayshtut static void 2139e21c39aaSAnton Nayshtut aio_fsdev_destroy_cb(void *io_device, void *ctx_buf) 2140e21c39aaSAnton Nayshtut { 2141e21c39aaSAnton Nayshtut struct aio_io_channel *ch = ctx_buf; 2142e21c39aaSAnton Nayshtut struct spdk_thread *thread = spdk_get_thread(); 2143e21c39aaSAnton Nayshtut 2144e21c39aaSAnton Nayshtut UNUSED(thread); 2145e21c39aaSAnton Nayshtut 2146e21c39aaSAnton Nayshtut spdk_poller_unregister(&ch->poller); 2147e21c39aaSAnton Nayshtut spdk_aio_mgr_delete(ch->mgr); 2148e21c39aaSAnton Nayshtut 2149e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "Destroyed aio fsdev IO channel: thread %s, thread id %" PRIu64 2150e21c39aaSAnton Nayshtut "\n", 2151e21c39aaSAnton Nayshtut spdk_thread_get_name(thread), spdk_thread_get_id(thread)); 2152e21c39aaSAnton Nayshtut } 2153e21c39aaSAnton Nayshtut 2154e21c39aaSAnton Nayshtut static int 2155e21c39aaSAnton Nayshtut fsdev_aio_initialize(void) 2156e21c39aaSAnton Nayshtut { 2157e21c39aaSAnton Nayshtut /* 2158e21c39aaSAnton Nayshtut * We need to pick some unique address as our "io device" - so just use the 2159e21c39aaSAnton Nayshtut * address of the global tailq. 2160e21c39aaSAnton Nayshtut */ 2161e21c39aaSAnton Nayshtut spdk_io_device_register(&g_aio_fsdev_head, 2162e21c39aaSAnton Nayshtut aio_fsdev_create_cb, aio_fsdev_destroy_cb, 2163e21c39aaSAnton Nayshtut sizeof(struct aio_io_channel), "aio_fsdev"); 2164e21c39aaSAnton Nayshtut 2165e21c39aaSAnton Nayshtut return 0; 2166e21c39aaSAnton Nayshtut } 2167e21c39aaSAnton Nayshtut 2168e21c39aaSAnton Nayshtut static void 2169e21c39aaSAnton Nayshtut _fsdev_aio_finish_cb(void *arg) 2170e21c39aaSAnton Nayshtut { 2171e21c39aaSAnton Nayshtut /* @todo: handle async module fini */ 2172e21c39aaSAnton Nayshtut /* spdk_fsdev_module_fini_done(); */ 2173e21c39aaSAnton Nayshtut } 2174e21c39aaSAnton Nayshtut 2175e21c39aaSAnton Nayshtut static void 2176e21c39aaSAnton Nayshtut fsdev_aio_finish(void) 2177e21c39aaSAnton Nayshtut { 2178e21c39aaSAnton Nayshtut spdk_io_device_unregister(&g_aio_fsdev_head, _fsdev_aio_finish_cb); 2179e21c39aaSAnton Nayshtut } 2180e21c39aaSAnton Nayshtut 2181e21c39aaSAnton Nayshtut static int 2182e21c39aaSAnton Nayshtut fsdev_aio_get_ctx_size(void) 2183e21c39aaSAnton Nayshtut { 2184e21c39aaSAnton Nayshtut return sizeof(struct aio_fsdev_io); 2185e21c39aaSAnton Nayshtut } 2186e21c39aaSAnton Nayshtut 2187e21c39aaSAnton Nayshtut static struct spdk_fsdev_module aio_fsdev_module = { 2188e21c39aaSAnton Nayshtut .name = "aio", 2189e21c39aaSAnton Nayshtut .module_init = fsdev_aio_initialize, 2190e21c39aaSAnton Nayshtut .module_fini = fsdev_aio_finish, 2191e21c39aaSAnton Nayshtut .get_ctx_size = fsdev_aio_get_ctx_size, 2192e21c39aaSAnton Nayshtut }; 2193e21c39aaSAnton Nayshtut 2194e21c39aaSAnton Nayshtut SPDK_FSDEV_MODULE_REGISTER(aio, &aio_fsdev_module); 2195e21c39aaSAnton Nayshtut 2196e21c39aaSAnton Nayshtut static void 2197e21c39aaSAnton Nayshtut fsdev_aio_free(struct aio_fsdev *vfsdev) 2198e21c39aaSAnton Nayshtut { 2199e21c39aaSAnton Nayshtut if (vfsdev->proc_self_fd != -1) { 2200e21c39aaSAnton Nayshtut close(vfsdev->proc_self_fd); 2201e21c39aaSAnton Nayshtut } 2202e21c39aaSAnton Nayshtut 2203e21c39aaSAnton Nayshtut if (vfsdev->root) { 2204e21c39aaSAnton Nayshtut int destroyed = file_object_unref(vfsdev->root, 1); 2205e21c39aaSAnton Nayshtut assert(destroyed == 0); 2206e21c39aaSAnton Nayshtut UNUSED(destroyed); 2207e21c39aaSAnton Nayshtut 2208e21c39aaSAnton Nayshtut } 2209e21c39aaSAnton Nayshtut 2210e21c39aaSAnton Nayshtut free(vfsdev->fsdev.name); 2211e21c39aaSAnton Nayshtut free(vfsdev->root_path); 2212e21c39aaSAnton Nayshtut 2213e21c39aaSAnton Nayshtut free(vfsdev); 2214e21c39aaSAnton Nayshtut } 2215e21c39aaSAnton Nayshtut 2216e21c39aaSAnton Nayshtut static int 2217e21c39aaSAnton Nayshtut fsdev_aio_destruct(void *ctx) 2218e21c39aaSAnton Nayshtut { 2219e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = ctx; 2220e21c39aaSAnton Nayshtut 2221e21c39aaSAnton Nayshtut TAILQ_REMOVE(&g_aio_fsdev_head, vfsdev, tailq); 2222e21c39aaSAnton Nayshtut 2223*6cb9c75cSAnton Nayshtut fsdev_free_leafs(vfsdev->root, true); 2224e21c39aaSAnton Nayshtut vfsdev->root = NULL; 2225e21c39aaSAnton Nayshtut 2226e21c39aaSAnton Nayshtut pthread_mutex_destroy(&vfsdev->mutex); 2227e21c39aaSAnton Nayshtut 2228e21c39aaSAnton Nayshtut fsdev_aio_free(vfsdev); 2229e21c39aaSAnton Nayshtut return 0; 2230e21c39aaSAnton Nayshtut } 2231e21c39aaSAnton Nayshtut 2232e21c39aaSAnton Nayshtut typedef int (*fsdev_op_handler_func)(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io); 2233e21c39aaSAnton Nayshtut 2234e21c39aaSAnton Nayshtut static fsdev_op_handler_func handlers[] = { 2235*6cb9c75cSAnton Nayshtut [SPDK_FSDEV_IO_MOUNT] = lo_mount, 2236*6cb9c75cSAnton Nayshtut [SPDK_FSDEV_IO_UMOUNT] = lo_umount, 2237e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_LOOKUP] = lo_lookup, 2238e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_FORGET] = lo_forget, 2239e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_GETATTR] = lo_getattr, 2240e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_SETATTR] = lo_setattr, 2241e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_READLINK] = lo_readlink, 2242e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_SYMLINK] = lo_symlink, 2243e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_MKNOD] = lo_mknod, 2244e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_MKDIR] = lo_mkdir, 2245e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_UNLINK] = lo_unlink, 2246e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_RMDIR] = lo_rmdir, 2247e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_RENAME] = lo_rename, 2248e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_LINK] = lo_link, 2249e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_OPEN] = lo_open, 2250e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_READ] = lo_read, 2251e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_WRITE] = lo_write, 2252e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_STATFS] = lo_statfs, 2253e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_RELEASE] = lo_release, 2254e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_FSYNC] = lo_fsync, 2255e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_SETXATTR] = lo_setxattr, 2256e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_GETXATTR] = lo_getxattr, 2257e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_LISTXATTR] = lo_listxattr, 2258e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_REMOVEXATTR] = lo_removexattr, 2259e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_FLUSH] = lo_flush, 2260e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_OPENDIR] = lo_opendir, 2261e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_READDIR] = lo_readdir, 2262e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_RELEASEDIR] = lo_releasedir, 2263e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_FSYNCDIR] = lo_fsyncdir, 2264e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_FLOCK] = lo_flock, 2265e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_CREATE] = lo_create, 2266e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_ABORT] = lo_abort, 2267e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_FALLOCATE] = lo_fallocate, 2268e21c39aaSAnton Nayshtut [SPDK_FSDEV_IO_COPY_FILE_RANGE] = lo_copy_file_range, 2269e21c39aaSAnton Nayshtut }; 2270e21c39aaSAnton Nayshtut 2271e21c39aaSAnton Nayshtut static void 2272e21c39aaSAnton Nayshtut fsdev_aio_submit_request(struct spdk_io_channel *ch, struct spdk_fsdev_io *fsdev_io) 2273e21c39aaSAnton Nayshtut { 2274e21c39aaSAnton Nayshtut int status; 2275e21c39aaSAnton Nayshtut enum spdk_fsdev_io_type type = spdk_fsdev_io_get_type(fsdev_io); 2276e21c39aaSAnton Nayshtut 2277e21c39aaSAnton Nayshtut assert(type >= 0 && type < __SPDK_FSDEV_IO_LAST); 2278e21c39aaSAnton Nayshtut 2279e21c39aaSAnton Nayshtut status = handlers[type](ch, fsdev_io); 2280e21c39aaSAnton Nayshtut if (status != IO_STATUS_ASYNC) { 2281e21c39aaSAnton Nayshtut spdk_fsdev_io_complete(fsdev_io, status); 2282e21c39aaSAnton Nayshtut } 2283e21c39aaSAnton Nayshtut } 2284e21c39aaSAnton Nayshtut 2285e21c39aaSAnton Nayshtut static struct spdk_io_channel * 2286e21c39aaSAnton Nayshtut fsdev_aio_get_io_channel(void *ctx) 2287e21c39aaSAnton Nayshtut { 2288e21c39aaSAnton Nayshtut return spdk_get_io_channel(&g_aio_fsdev_head); 2289e21c39aaSAnton Nayshtut } 2290e21c39aaSAnton Nayshtut 2291e21c39aaSAnton Nayshtut static void 2292e21c39aaSAnton Nayshtut fsdev_aio_write_config_json(struct spdk_fsdev *fsdev, struct spdk_json_write_ctx *w) 2293e21c39aaSAnton Nayshtut { 2294e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev = fsdev_to_aio_fsdev(fsdev); 2295e21c39aaSAnton Nayshtut 2296e21c39aaSAnton Nayshtut spdk_json_write_object_begin(w); 2297e21c39aaSAnton Nayshtut spdk_json_write_named_string(w, "method", "fsdev_aio_create"); 2298e21c39aaSAnton Nayshtut spdk_json_write_named_object_begin(w, "params"); 2299e21c39aaSAnton Nayshtut spdk_json_write_named_string(w, "name", spdk_fsdev_get_name(&vfsdev->fsdev)); 2300e21c39aaSAnton Nayshtut spdk_json_write_named_string(w, "root_path", vfsdev->root_path); 2301e21c39aaSAnton Nayshtut spdk_json_write_named_bool(w, "enable_xattr", vfsdev->xattr_enabled); 2302e21c39aaSAnton Nayshtut spdk_json_write_named_bool(w, "enable_writeback_cache", 2303*6cb9c75cSAnton Nayshtut !!vfsdev->mount_opts.writeback_cache_enabled); 2304*6cb9c75cSAnton Nayshtut spdk_json_write_named_uint32(w, "max_write", vfsdev->mount_opts.max_write); 230592108e0aSYoray Zack spdk_json_write_named_bool(w, "skip_rw", vfsdev->skip_rw); 2306e21c39aaSAnton Nayshtut spdk_json_write_object_end(w); /* params */ 2307e21c39aaSAnton Nayshtut spdk_json_write_object_end(w); 2308e21c39aaSAnton Nayshtut } 2309e21c39aaSAnton Nayshtut 2310e21c39aaSAnton Nayshtut static const struct spdk_fsdev_fn_table aio_fn_table = { 2311e21c39aaSAnton Nayshtut .destruct = fsdev_aio_destruct, 2312e21c39aaSAnton Nayshtut .submit_request = fsdev_aio_submit_request, 2313e21c39aaSAnton Nayshtut .get_io_channel = fsdev_aio_get_io_channel, 2314e21c39aaSAnton Nayshtut .write_config_json = fsdev_aio_write_config_json, 2315e21c39aaSAnton Nayshtut }; 2316e21c39aaSAnton Nayshtut 2317e21c39aaSAnton Nayshtut static int 2318e21c39aaSAnton Nayshtut setup_root(struct aio_fsdev *vfsdev) 2319e21c39aaSAnton Nayshtut { 2320e21c39aaSAnton Nayshtut int fd, res; 2321e21c39aaSAnton Nayshtut struct stat stat; 2322e21c39aaSAnton Nayshtut 2323e21c39aaSAnton Nayshtut fd = open(vfsdev->root_path, O_PATH); 2324e21c39aaSAnton Nayshtut if (fd == -1) { 2325e21c39aaSAnton Nayshtut res = -errno; 2326e21c39aaSAnton Nayshtut SPDK_ERRLOG("Cannot open root %s (err=%d)\n", vfsdev->root_path, res); 2327e21c39aaSAnton Nayshtut return res; 2328e21c39aaSAnton Nayshtut } 2329e21c39aaSAnton Nayshtut 2330e21c39aaSAnton Nayshtut res = fstatat(fd, "", &stat, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); 2331e21c39aaSAnton Nayshtut if (res == -1) { 2332e21c39aaSAnton Nayshtut res = -errno; 2333e21c39aaSAnton Nayshtut SPDK_ERRLOG("Cannot get root fstatat of %s (err=%d)\n", vfsdev->root_path, res); 2334e21c39aaSAnton Nayshtut close(fd); 2335e21c39aaSAnton Nayshtut return res; 2336e21c39aaSAnton Nayshtut } 2337e21c39aaSAnton Nayshtut 2338e21c39aaSAnton Nayshtut vfsdev->root = file_object_create_unsafe(NULL, fd, stat.st_ino, stat.st_dev, stat.st_mode); 2339e21c39aaSAnton Nayshtut if (!vfsdev->root) { 2340e21c39aaSAnton Nayshtut SPDK_ERRLOG("Cannot alloc root\n"); 2341e21c39aaSAnton Nayshtut close(fd); 2342e21c39aaSAnton Nayshtut return -ENOMEM; 2343e21c39aaSAnton Nayshtut } 2344e21c39aaSAnton Nayshtut 2345e21c39aaSAnton Nayshtut SPDK_INFOLOG(fsdev_aio, "root (%s) fd=%d\n", vfsdev->root_path, fd); 2346e21c39aaSAnton Nayshtut return 0; 2347e21c39aaSAnton Nayshtut } 2348e21c39aaSAnton Nayshtut 2349e21c39aaSAnton Nayshtut static int 2350e21c39aaSAnton Nayshtut setup_proc_self_fd(struct aio_fsdev *vfsdev) 2351e21c39aaSAnton Nayshtut { 2352e21c39aaSAnton Nayshtut vfsdev->proc_self_fd = open("/proc/self/fd", O_PATH); 2353e21c39aaSAnton Nayshtut if (vfsdev->proc_self_fd == -1) { 2354e21c39aaSAnton Nayshtut int saverr = -errno; 2355e21c39aaSAnton Nayshtut SPDK_ERRLOG("Failed to open procfs fd dir with %d\n", saverr); 2356e21c39aaSAnton Nayshtut return saverr; 2357e21c39aaSAnton Nayshtut } 2358e21c39aaSAnton Nayshtut 2359e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "procfs fd dir opened (fd=%d)\n", vfsdev->proc_self_fd); 2360e21c39aaSAnton Nayshtut return 0; 2361e21c39aaSAnton Nayshtut } 2362e21c39aaSAnton Nayshtut 2363e21c39aaSAnton Nayshtut void 2364e21c39aaSAnton Nayshtut spdk_fsdev_aio_get_default_opts(struct spdk_fsdev_aio_opts *opts) 2365e21c39aaSAnton Nayshtut { 2366e21c39aaSAnton Nayshtut assert(opts); 2367e21c39aaSAnton Nayshtut 2368e21c39aaSAnton Nayshtut memset(opts, 0, sizeof(*opts)); 2369e21c39aaSAnton Nayshtut 2370e21c39aaSAnton Nayshtut opts->xattr_enabled = DEFAULT_XATTR_ENABLED; 2371e21c39aaSAnton Nayshtut opts->writeback_cache_enabled = DEFAULT_WRITEBACK_CACHE; 2372e21c39aaSAnton Nayshtut opts->max_write = DEFAULT_MAX_WRITE; 237392108e0aSYoray Zack opts->skip_rw = DEFAULT_SKIP_RW; 2374e21c39aaSAnton Nayshtut } 2375e21c39aaSAnton Nayshtut 2376e21c39aaSAnton Nayshtut int 2377e21c39aaSAnton Nayshtut spdk_fsdev_aio_create(struct spdk_fsdev **fsdev, const char *name, const char *root_path, 2378e21c39aaSAnton Nayshtut const struct spdk_fsdev_aio_opts *opts) 2379e21c39aaSAnton Nayshtut { 2380e21c39aaSAnton Nayshtut struct aio_fsdev *vfsdev; 2381e21c39aaSAnton Nayshtut int rc; 2382e21c39aaSAnton Nayshtut 2383e21c39aaSAnton Nayshtut vfsdev = calloc(1, sizeof(*vfsdev)); 2384e21c39aaSAnton Nayshtut if (!vfsdev) { 2385e21c39aaSAnton Nayshtut SPDK_ERRLOG("Could not allocate aio_fsdev\n"); 2386e21c39aaSAnton Nayshtut return -ENOMEM; 2387e21c39aaSAnton Nayshtut } 2388e21c39aaSAnton Nayshtut 2389e21c39aaSAnton Nayshtut vfsdev->proc_self_fd = -1; 2390e21c39aaSAnton Nayshtut 2391e21c39aaSAnton Nayshtut vfsdev->fsdev.name = strdup(name); 2392e21c39aaSAnton Nayshtut if (!vfsdev->fsdev.name) { 2393e21c39aaSAnton Nayshtut SPDK_ERRLOG("Could not strdup fsdev name: %s\n", name); 2394e21c39aaSAnton Nayshtut fsdev_aio_free(vfsdev); 2395e21c39aaSAnton Nayshtut return -ENOMEM; 2396e21c39aaSAnton Nayshtut } 2397e21c39aaSAnton Nayshtut 2398e21c39aaSAnton Nayshtut vfsdev->root_path = strdup(root_path); 2399e21c39aaSAnton Nayshtut if (!vfsdev->root_path) { 2400e21c39aaSAnton Nayshtut SPDK_ERRLOG("Could not strdup root path: %s\n", root_path); 2401e21c39aaSAnton Nayshtut fsdev_aio_free(vfsdev); 2402e21c39aaSAnton Nayshtut return -ENOMEM; 2403e21c39aaSAnton Nayshtut } 2404e21c39aaSAnton Nayshtut 2405e21c39aaSAnton Nayshtut rc = setup_root(vfsdev); 2406e21c39aaSAnton Nayshtut if (rc) { 2407e21c39aaSAnton Nayshtut SPDK_ERRLOG("Could not setup root: %s (err=%d)\n", root_path, rc); 2408e21c39aaSAnton Nayshtut fsdev_aio_free(vfsdev); 2409e21c39aaSAnton Nayshtut return rc; 2410e21c39aaSAnton Nayshtut } 2411e21c39aaSAnton Nayshtut 2412e21c39aaSAnton Nayshtut rc = setup_proc_self_fd(vfsdev); 2413e21c39aaSAnton Nayshtut if (rc) { 2414e21c39aaSAnton Nayshtut SPDK_ERRLOG("Could not setup proc_self_fd (err=%d)\n", rc); 2415e21c39aaSAnton Nayshtut fsdev_aio_free(vfsdev); 2416e21c39aaSAnton Nayshtut return rc; 2417e21c39aaSAnton Nayshtut } 2418e21c39aaSAnton Nayshtut 2419e21c39aaSAnton Nayshtut if (opts->xattr_enabled) { 2420e21c39aaSAnton Nayshtut SPDK_ERRLOG("Extended attributes can only be enabled in Linux\n"); 2421e21c39aaSAnton Nayshtut fsdev_aio_free(vfsdev); 2422e21c39aaSAnton Nayshtut return rc; 2423e21c39aaSAnton Nayshtut } 2424e21c39aaSAnton Nayshtut 2425e21c39aaSAnton Nayshtut vfsdev->xattr_enabled = opts->xattr_enabled; 2426e21c39aaSAnton Nayshtut vfsdev->fsdev.ctxt = vfsdev; 2427e21c39aaSAnton Nayshtut vfsdev->fsdev.fn_table = &aio_fn_table; 2428e21c39aaSAnton Nayshtut vfsdev->fsdev.module = &aio_fsdev_module; 2429e21c39aaSAnton Nayshtut 2430e21c39aaSAnton Nayshtut pthread_mutex_init(&vfsdev->mutex, NULL); 2431e21c39aaSAnton Nayshtut 2432e21c39aaSAnton Nayshtut rc = spdk_fsdev_register(&vfsdev->fsdev); 2433e21c39aaSAnton Nayshtut if (rc) { 2434e21c39aaSAnton Nayshtut fsdev_aio_free(vfsdev); 2435e21c39aaSAnton Nayshtut return rc; 2436e21c39aaSAnton Nayshtut } 2437e21c39aaSAnton Nayshtut 2438*6cb9c75cSAnton Nayshtut vfsdev->mount_opts.writeback_cache_enabled = DEFAULT_WRITEBACK_CACHE; 2439*6cb9c75cSAnton Nayshtut vfsdev->mount_opts.max_write = DEFAULT_MAX_WRITE; 2440e21c39aaSAnton Nayshtut 244192108e0aSYoray Zack vfsdev->skip_rw = opts->skip_rw; 244292108e0aSYoray Zack 2443e21c39aaSAnton Nayshtut *fsdev = &(vfsdev->fsdev); 2444e21c39aaSAnton Nayshtut TAILQ_INSERT_TAIL(&g_aio_fsdev_head, vfsdev, tailq); 2445e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "Created aio filesystem %s (xattr_enabled=%" PRIu8 " writeback_cache=%" 244692108e0aSYoray Zack PRIu8 " max_write=%" PRIu32 " skip_rw=%" PRIu8 ")\n", 2447*6cb9c75cSAnton Nayshtut vfsdev->fsdev.name, vfsdev->xattr_enabled, vfsdev->mount_opts.writeback_cache_enabled, 2448*6cb9c75cSAnton Nayshtut vfsdev->mount_opts.max_write, vfsdev->skip_rw); 2449e21c39aaSAnton Nayshtut return rc; 2450e21c39aaSAnton Nayshtut } 2451e21c39aaSAnton Nayshtut void 2452e21c39aaSAnton Nayshtut spdk_fsdev_aio_delete(const char *name, 2453e21c39aaSAnton Nayshtut spdk_delete_aio_fsdev_complete cb_fn, void *cb_arg) 2454e21c39aaSAnton Nayshtut { 2455e21c39aaSAnton Nayshtut int rc; 2456e21c39aaSAnton Nayshtut 2457e21c39aaSAnton Nayshtut rc = spdk_fsdev_unregister_by_name(name, &aio_fsdev_module, cb_fn, cb_arg); 2458e21c39aaSAnton Nayshtut if (rc != 0) { 2459e21c39aaSAnton Nayshtut cb_fn(cb_arg, rc); 2460e21c39aaSAnton Nayshtut } 2461e21c39aaSAnton Nayshtut 2462e21c39aaSAnton Nayshtut SPDK_DEBUGLOG(fsdev_aio, "Deleted aio filesystem %s\n", name); 2463e21c39aaSAnton Nayshtut } 2464e21c39aaSAnton Nayshtut 2465e21c39aaSAnton Nayshtut SPDK_LOG_REGISTER_COMPONENT(fsdev_aio) 2466