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