1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2017 Red Hat, Inc. 4 */ 5 6 #include <linux/cred.h> 7 #include <linux/file.h> 8 #include <linux/mount.h> 9 #include <linux/xattr.h> 10 #include <linux/uio.h> 11 #include <linux/uaccess.h> 12 #include <linux/splice.h> 13 #include <linux/mm.h> 14 #include <linux/fs.h> 15 #include "overlayfs.h" 16 17 struct ovl_aio_req { 18 struct kiocb iocb; 19 struct kiocb *orig_iocb; 20 struct fd fd; 21 }; 22 23 static struct kmem_cache *ovl_aio_request_cachep; 24 25 static char ovl_whatisit(struct inode *inode, struct inode *realinode) 26 { 27 if (realinode != ovl_inode_upper(inode)) 28 return 'l'; 29 if (ovl_has_upperdata(inode)) 30 return 'u'; 31 else 32 return 'm'; 33 } 34 35 static struct file *ovl_open_realfile(const struct file *file, 36 struct inode *realinode) 37 { 38 struct inode *inode = file_inode(file); 39 struct file *realfile; 40 const struct cred *old_cred; 41 int flags = file->f_flags | O_NOATIME | FMODE_NONOTIFY; 42 43 old_cred = ovl_override_creds(inode->i_sb); 44 realfile = open_with_fake_path(&file->f_path, flags, realinode, 45 current_cred()); 46 revert_creds(old_cred); 47 48 pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n", 49 file, file, ovl_whatisit(inode, realinode), file->f_flags, 50 realfile, IS_ERR(realfile) ? 0 : realfile->f_flags); 51 52 return realfile; 53 } 54 55 #define OVL_SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT) 56 57 static int ovl_change_flags(struct file *file, unsigned int flags) 58 { 59 struct inode *inode = file_inode(file); 60 int err; 61 62 /* No atime modificaton on underlying */ 63 flags |= O_NOATIME | FMODE_NONOTIFY; 64 65 /* If some flag changed that cannot be changed then something's amiss */ 66 if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK)) 67 return -EIO; 68 69 flags &= OVL_SETFL_MASK; 70 71 if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode)) 72 return -EPERM; 73 74 if (flags & O_DIRECT) { 75 if (!file->f_mapping->a_ops || 76 !file->f_mapping->a_ops->direct_IO) 77 return -EINVAL; 78 } 79 80 if (file->f_op->check_flags) { 81 err = file->f_op->check_flags(flags); 82 if (err) 83 return err; 84 } 85 86 spin_lock(&file->f_lock); 87 file->f_flags = (file->f_flags & ~OVL_SETFL_MASK) | flags; 88 spin_unlock(&file->f_lock); 89 90 return 0; 91 } 92 93 static int ovl_real_fdget_meta(const struct file *file, struct fd *real, 94 bool allow_meta) 95 { 96 struct inode *inode = file_inode(file); 97 struct inode *realinode; 98 99 real->flags = 0; 100 real->file = file->private_data; 101 102 if (allow_meta) 103 realinode = ovl_inode_real(inode); 104 else 105 realinode = ovl_inode_realdata(inode); 106 107 /* Has it been copied up since we'd opened it? */ 108 if (unlikely(file_inode(real->file) != realinode)) { 109 real->flags = FDPUT_FPUT; 110 real->file = ovl_open_realfile(file, realinode); 111 112 return PTR_ERR_OR_ZERO(real->file); 113 } 114 115 /* Did the flags change since open? */ 116 if (unlikely((file->f_flags ^ real->file->f_flags) & ~O_NOATIME)) 117 return ovl_change_flags(real->file, file->f_flags); 118 119 return 0; 120 } 121 122 static int ovl_real_fdget(const struct file *file, struct fd *real) 123 { 124 return ovl_real_fdget_meta(file, real, false); 125 } 126 127 static int ovl_open(struct inode *inode, struct file *file) 128 { 129 struct file *realfile; 130 int err; 131 132 err = ovl_maybe_copy_up(file_dentry(file), file->f_flags); 133 if (err) 134 return err; 135 136 /* No longer need these flags, so don't pass them on to underlying fs */ 137 file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); 138 139 realfile = ovl_open_realfile(file, ovl_inode_realdata(inode)); 140 if (IS_ERR(realfile)) 141 return PTR_ERR(realfile); 142 143 file->private_data = realfile; 144 145 return 0; 146 } 147 148 static int ovl_release(struct inode *inode, struct file *file) 149 { 150 fput(file->private_data); 151 152 return 0; 153 } 154 155 static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) 156 { 157 struct inode *inode = file_inode(file); 158 struct fd real; 159 const struct cred *old_cred; 160 loff_t ret; 161 162 /* 163 * The two special cases below do not need to involve real fs, 164 * so we can optimizing concurrent callers. 165 */ 166 if (offset == 0) { 167 if (whence == SEEK_CUR) 168 return file->f_pos; 169 170 if (whence == SEEK_SET) 171 return vfs_setpos(file, 0, 0); 172 } 173 174 ret = ovl_real_fdget(file, &real); 175 if (ret) 176 return ret; 177 178 /* 179 * Overlay file f_pos is the master copy that is preserved 180 * through copy up and modified on read/write, but only real 181 * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose 182 * limitations that are more strict than ->s_maxbytes for specific 183 * files, so we use the real file to perform seeks. 184 */ 185 ovl_inode_lock(inode); 186 real.file->f_pos = file->f_pos; 187 188 old_cred = ovl_override_creds(inode->i_sb); 189 ret = vfs_llseek(real.file, offset, whence); 190 revert_creds(old_cred); 191 192 file->f_pos = real.file->f_pos; 193 ovl_inode_unlock(inode); 194 195 fdput(real); 196 197 return ret; 198 } 199 200 static void ovl_file_accessed(struct file *file) 201 { 202 struct inode *inode, *upperinode; 203 204 if (file->f_flags & O_NOATIME) 205 return; 206 207 inode = file_inode(file); 208 upperinode = ovl_inode_upper(inode); 209 210 if (!upperinode) 211 return; 212 213 if ((!timespec64_equal(&inode->i_mtime, &upperinode->i_mtime) || 214 !timespec64_equal(&inode->i_ctime, &upperinode->i_ctime))) { 215 inode->i_mtime = upperinode->i_mtime; 216 inode->i_ctime = upperinode->i_ctime; 217 } 218 219 touch_atime(&file->f_path); 220 } 221 222 static rwf_t ovl_iocb_to_rwf(struct kiocb *iocb) 223 { 224 int ifl = iocb->ki_flags; 225 rwf_t flags = 0; 226 227 if (ifl & IOCB_NOWAIT) 228 flags |= RWF_NOWAIT; 229 if (ifl & IOCB_HIPRI) 230 flags |= RWF_HIPRI; 231 if (ifl & IOCB_DSYNC) 232 flags |= RWF_DSYNC; 233 if (ifl & IOCB_SYNC) 234 flags |= RWF_SYNC; 235 236 return flags; 237 } 238 239 static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req) 240 { 241 struct kiocb *iocb = &aio_req->iocb; 242 struct kiocb *orig_iocb = aio_req->orig_iocb; 243 244 if (iocb->ki_flags & IOCB_WRITE) { 245 struct inode *inode = file_inode(orig_iocb->ki_filp); 246 247 /* Actually acquired in ovl_write_iter() */ 248 __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb, 249 SB_FREEZE_WRITE); 250 file_end_write(iocb->ki_filp); 251 ovl_copyattr(ovl_inode_real(inode), inode); 252 } 253 254 orig_iocb->ki_pos = iocb->ki_pos; 255 fdput(aio_req->fd); 256 kmem_cache_free(ovl_aio_request_cachep, aio_req); 257 } 258 259 static void ovl_aio_rw_complete(struct kiocb *iocb, long res, long res2) 260 { 261 struct ovl_aio_req *aio_req = container_of(iocb, 262 struct ovl_aio_req, iocb); 263 struct kiocb *orig_iocb = aio_req->orig_iocb; 264 265 ovl_aio_cleanup_handler(aio_req); 266 orig_iocb->ki_complete(orig_iocb, res, res2); 267 } 268 269 static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter) 270 { 271 struct file *file = iocb->ki_filp; 272 struct fd real; 273 const struct cred *old_cred; 274 ssize_t ret; 275 276 if (!iov_iter_count(iter)) 277 return 0; 278 279 ret = ovl_real_fdget(file, &real); 280 if (ret) 281 return ret; 282 283 old_cred = ovl_override_creds(file_inode(file)->i_sb); 284 if (is_sync_kiocb(iocb)) { 285 ret = vfs_iter_read(real.file, iter, &iocb->ki_pos, 286 ovl_iocb_to_rwf(iocb)); 287 } else { 288 struct ovl_aio_req *aio_req; 289 290 ret = -ENOMEM; 291 aio_req = kmem_cache_zalloc(ovl_aio_request_cachep, GFP_KERNEL); 292 if (!aio_req) 293 goto out; 294 295 aio_req->fd = real; 296 real.flags = 0; 297 aio_req->orig_iocb = iocb; 298 kiocb_clone(&aio_req->iocb, iocb, real.file); 299 aio_req->iocb.ki_complete = ovl_aio_rw_complete; 300 ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter); 301 if (ret != -EIOCBQUEUED) 302 ovl_aio_cleanup_handler(aio_req); 303 } 304 out: 305 revert_creds(old_cred); 306 ovl_file_accessed(file); 307 308 fdput(real); 309 310 return ret; 311 } 312 313 static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter) 314 { 315 struct file *file = iocb->ki_filp; 316 struct inode *inode = file_inode(file); 317 struct fd real; 318 const struct cred *old_cred; 319 ssize_t ret; 320 321 if (!iov_iter_count(iter)) 322 return 0; 323 324 inode_lock(inode); 325 /* Update mode */ 326 ovl_copyattr(ovl_inode_real(inode), inode); 327 ret = file_remove_privs(file); 328 if (ret) 329 goto out_unlock; 330 331 ret = ovl_real_fdget(file, &real); 332 if (ret) 333 goto out_unlock; 334 335 old_cred = ovl_override_creds(file_inode(file)->i_sb); 336 if (is_sync_kiocb(iocb)) { 337 file_start_write(real.file); 338 ret = vfs_iter_write(real.file, iter, &iocb->ki_pos, 339 ovl_iocb_to_rwf(iocb)); 340 file_end_write(real.file); 341 /* Update size */ 342 ovl_copyattr(ovl_inode_real(inode), inode); 343 } else { 344 struct ovl_aio_req *aio_req; 345 346 ret = -ENOMEM; 347 aio_req = kmem_cache_zalloc(ovl_aio_request_cachep, GFP_KERNEL); 348 if (!aio_req) 349 goto out; 350 351 file_start_write(real.file); 352 /* Pacify lockdep, same trick as done in aio_write() */ 353 __sb_writers_release(file_inode(real.file)->i_sb, 354 SB_FREEZE_WRITE); 355 aio_req->fd = real; 356 real.flags = 0; 357 aio_req->orig_iocb = iocb; 358 kiocb_clone(&aio_req->iocb, iocb, real.file); 359 aio_req->iocb.ki_complete = ovl_aio_rw_complete; 360 ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter); 361 if (ret != -EIOCBQUEUED) 362 ovl_aio_cleanup_handler(aio_req); 363 } 364 out: 365 revert_creds(old_cred); 366 fdput(real); 367 368 out_unlock: 369 inode_unlock(inode); 370 371 return ret; 372 } 373 374 static ssize_t ovl_splice_read(struct file *in, loff_t *ppos, 375 struct pipe_inode_info *pipe, size_t len, 376 unsigned int flags) 377 { 378 ssize_t ret; 379 struct fd real; 380 const struct cred *old_cred; 381 382 ret = ovl_real_fdget(in, &real); 383 if (ret) 384 return ret; 385 386 old_cred = ovl_override_creds(file_inode(in)->i_sb); 387 ret = generic_file_splice_read(real.file, ppos, pipe, len, flags); 388 revert_creds(old_cred); 389 390 ovl_file_accessed(in); 391 fdput(real); 392 return ret; 393 } 394 395 static ssize_t 396 ovl_splice_write(struct pipe_inode_info *pipe, struct file *out, 397 loff_t *ppos, size_t len, unsigned int flags) 398 { 399 struct fd real; 400 const struct cred *old_cred; 401 ssize_t ret; 402 403 ret = ovl_real_fdget(out, &real); 404 if (ret) 405 return ret; 406 407 old_cred = ovl_override_creds(file_inode(out)->i_sb); 408 ret = iter_file_splice_write(pipe, real.file, ppos, len, flags); 409 revert_creds(old_cred); 410 411 ovl_file_accessed(out); 412 fdput(real); 413 return ret; 414 } 415 416 static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync) 417 { 418 struct fd real; 419 const struct cred *old_cred; 420 int ret; 421 422 ret = ovl_real_fdget_meta(file, &real, !datasync); 423 if (ret) 424 return ret; 425 426 /* Don't sync lower file for fear of receiving EROFS error */ 427 if (file_inode(real.file) == ovl_inode_upper(file_inode(file))) { 428 old_cred = ovl_override_creds(file_inode(file)->i_sb); 429 ret = vfs_fsync_range(real.file, start, end, datasync); 430 revert_creds(old_cred); 431 } 432 433 fdput(real); 434 435 return ret; 436 } 437 438 static int ovl_mmap(struct file *file, struct vm_area_struct *vma) 439 { 440 struct file *realfile = file->private_data; 441 const struct cred *old_cred; 442 int ret; 443 444 if (!realfile->f_op->mmap) 445 return -ENODEV; 446 447 if (WARN_ON(file != vma->vm_file)) 448 return -EIO; 449 450 vma->vm_file = get_file(realfile); 451 452 old_cred = ovl_override_creds(file_inode(file)->i_sb); 453 ret = call_mmap(vma->vm_file, vma); 454 revert_creds(old_cred); 455 456 if (ret) { 457 /* Drop reference count from new vm_file value */ 458 fput(realfile); 459 } else { 460 /* Drop reference count from previous vm_file value */ 461 fput(file); 462 } 463 464 ovl_file_accessed(file); 465 466 return ret; 467 } 468 469 static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len) 470 { 471 struct inode *inode = file_inode(file); 472 struct fd real; 473 const struct cred *old_cred; 474 int ret; 475 476 ret = ovl_real_fdget(file, &real); 477 if (ret) 478 return ret; 479 480 old_cred = ovl_override_creds(file_inode(file)->i_sb); 481 ret = vfs_fallocate(real.file, mode, offset, len); 482 revert_creds(old_cred); 483 484 /* Update size */ 485 ovl_copyattr(ovl_inode_real(inode), inode); 486 487 fdput(real); 488 489 return ret; 490 } 491 492 static int ovl_fadvise(struct file *file, loff_t offset, loff_t len, int advice) 493 { 494 struct fd real; 495 const struct cred *old_cred; 496 int ret; 497 498 ret = ovl_real_fdget(file, &real); 499 if (ret) 500 return ret; 501 502 old_cred = ovl_override_creds(file_inode(file)->i_sb); 503 ret = vfs_fadvise(real.file, offset, len, advice); 504 revert_creds(old_cred); 505 506 fdput(real); 507 508 return ret; 509 } 510 511 static long ovl_real_ioctl(struct file *file, unsigned int cmd, 512 unsigned long arg) 513 { 514 struct fd real; 515 const struct cred *old_cred; 516 long ret; 517 518 ret = ovl_real_fdget(file, &real); 519 if (ret) 520 return ret; 521 522 old_cred = ovl_override_creds(file_inode(file)->i_sb); 523 ret = vfs_ioctl(real.file, cmd, arg); 524 revert_creds(old_cred); 525 526 fdput(real); 527 528 return ret; 529 } 530 531 static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, 532 unsigned long arg, unsigned int iflags) 533 { 534 long ret; 535 struct inode *inode = file_inode(file); 536 unsigned int old_iflags; 537 538 if (!inode_owner_or_capable(inode)) 539 return -EACCES; 540 541 ret = mnt_want_write_file(file); 542 if (ret) 543 return ret; 544 545 inode_lock(inode); 546 547 /* Check the capability before cred override */ 548 ret = -EPERM; 549 old_iflags = READ_ONCE(inode->i_flags); 550 if (((iflags ^ old_iflags) & (S_APPEND | S_IMMUTABLE)) && 551 !capable(CAP_LINUX_IMMUTABLE)) 552 goto unlock; 553 554 ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY); 555 if (ret) 556 goto unlock; 557 558 ret = ovl_real_ioctl(file, cmd, arg); 559 560 ovl_copyflags(ovl_inode_real(inode), inode); 561 unlock: 562 inode_unlock(inode); 563 564 mnt_drop_write_file(file); 565 566 return ret; 567 568 } 569 570 static unsigned int ovl_fsflags_to_iflags(unsigned int flags) 571 { 572 unsigned int iflags = 0; 573 574 if (flags & FS_SYNC_FL) 575 iflags |= S_SYNC; 576 if (flags & FS_APPEND_FL) 577 iflags |= S_APPEND; 578 if (flags & FS_IMMUTABLE_FL) 579 iflags |= S_IMMUTABLE; 580 if (flags & FS_NOATIME_FL) 581 iflags |= S_NOATIME; 582 583 return iflags; 584 } 585 586 static long ovl_ioctl_set_fsflags(struct file *file, unsigned int cmd, 587 unsigned long arg) 588 { 589 unsigned int flags; 590 591 if (get_user(flags, (int __user *) arg)) 592 return -EFAULT; 593 594 return ovl_ioctl_set_flags(file, cmd, arg, 595 ovl_fsflags_to_iflags(flags)); 596 } 597 598 static unsigned int ovl_fsxflags_to_iflags(unsigned int xflags) 599 { 600 unsigned int iflags = 0; 601 602 if (xflags & FS_XFLAG_SYNC) 603 iflags |= S_SYNC; 604 if (xflags & FS_XFLAG_APPEND) 605 iflags |= S_APPEND; 606 if (xflags & FS_XFLAG_IMMUTABLE) 607 iflags |= S_IMMUTABLE; 608 if (xflags & FS_XFLAG_NOATIME) 609 iflags |= S_NOATIME; 610 611 return iflags; 612 } 613 614 static long ovl_ioctl_set_fsxflags(struct file *file, unsigned int cmd, 615 unsigned long arg) 616 { 617 struct fsxattr fa; 618 619 memset(&fa, 0, sizeof(fa)); 620 if (copy_from_user(&fa, (void __user *) arg, sizeof(fa))) 621 return -EFAULT; 622 623 return ovl_ioctl_set_flags(file, cmd, arg, 624 ovl_fsxflags_to_iflags(fa.fsx_xflags)); 625 } 626 627 static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 628 { 629 long ret; 630 631 switch (cmd) { 632 case FS_IOC_GETFLAGS: 633 case FS_IOC_FSGETXATTR: 634 ret = ovl_real_ioctl(file, cmd, arg); 635 break; 636 637 case FS_IOC_SETFLAGS: 638 ret = ovl_ioctl_set_fsflags(file, cmd, arg); 639 break; 640 641 case FS_IOC_FSSETXATTR: 642 ret = ovl_ioctl_set_fsxflags(file, cmd, arg); 643 break; 644 645 default: 646 ret = -ENOTTY; 647 } 648 649 return ret; 650 } 651 652 static long ovl_compat_ioctl(struct file *file, unsigned int cmd, 653 unsigned long arg) 654 { 655 switch (cmd) { 656 case FS_IOC32_GETFLAGS: 657 cmd = FS_IOC_GETFLAGS; 658 break; 659 660 case FS_IOC32_SETFLAGS: 661 cmd = FS_IOC_SETFLAGS; 662 break; 663 664 default: 665 return -ENOIOCTLCMD; 666 } 667 668 return ovl_ioctl(file, cmd, arg); 669 } 670 671 enum ovl_copyop { 672 OVL_COPY, 673 OVL_CLONE, 674 OVL_DEDUPE, 675 }; 676 677 static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in, 678 struct file *file_out, loff_t pos_out, 679 loff_t len, unsigned int flags, enum ovl_copyop op) 680 { 681 struct inode *inode_out = file_inode(file_out); 682 struct fd real_in, real_out; 683 const struct cred *old_cred; 684 loff_t ret; 685 686 ret = ovl_real_fdget(file_out, &real_out); 687 if (ret) 688 return ret; 689 690 ret = ovl_real_fdget(file_in, &real_in); 691 if (ret) { 692 fdput(real_out); 693 return ret; 694 } 695 696 old_cred = ovl_override_creds(file_inode(file_out)->i_sb); 697 switch (op) { 698 case OVL_COPY: 699 ret = vfs_copy_file_range(real_in.file, pos_in, 700 real_out.file, pos_out, len, flags); 701 break; 702 703 case OVL_CLONE: 704 ret = vfs_clone_file_range(real_in.file, pos_in, 705 real_out.file, pos_out, len, flags); 706 break; 707 708 case OVL_DEDUPE: 709 ret = vfs_dedupe_file_range_one(real_in.file, pos_in, 710 real_out.file, pos_out, len, 711 flags); 712 break; 713 } 714 revert_creds(old_cred); 715 716 /* Update size */ 717 ovl_copyattr(ovl_inode_real(inode_out), inode_out); 718 719 fdput(real_in); 720 fdput(real_out); 721 722 return ret; 723 } 724 725 static ssize_t ovl_copy_file_range(struct file *file_in, loff_t pos_in, 726 struct file *file_out, loff_t pos_out, 727 size_t len, unsigned int flags) 728 { 729 return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, flags, 730 OVL_COPY); 731 } 732 733 static loff_t ovl_remap_file_range(struct file *file_in, loff_t pos_in, 734 struct file *file_out, loff_t pos_out, 735 loff_t len, unsigned int remap_flags) 736 { 737 enum ovl_copyop op; 738 739 if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) 740 return -EINVAL; 741 742 if (remap_flags & REMAP_FILE_DEDUP) 743 op = OVL_DEDUPE; 744 else 745 op = OVL_CLONE; 746 747 /* 748 * Don't copy up because of a dedupe request, this wouldn't make sense 749 * most of the time (data would be duplicated instead of deduplicated). 750 */ 751 if (op == OVL_DEDUPE && 752 (!ovl_inode_upper(file_inode(file_in)) || 753 !ovl_inode_upper(file_inode(file_out)))) 754 return -EPERM; 755 756 return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, 757 remap_flags, op); 758 } 759 760 const struct file_operations ovl_file_operations = { 761 .open = ovl_open, 762 .release = ovl_release, 763 .llseek = ovl_llseek, 764 .read_iter = ovl_read_iter, 765 .write_iter = ovl_write_iter, 766 .fsync = ovl_fsync, 767 .mmap = ovl_mmap, 768 .fallocate = ovl_fallocate, 769 .fadvise = ovl_fadvise, 770 .unlocked_ioctl = ovl_ioctl, 771 .compat_ioctl = ovl_compat_ioctl, 772 .splice_read = ovl_splice_read, 773 .splice_write = ovl_splice_write, 774 775 .copy_file_range = ovl_copy_file_range, 776 .remap_file_range = ovl_remap_file_range, 777 }; 778 779 int __init ovl_aio_request_cache_init(void) 780 { 781 ovl_aio_request_cachep = kmem_cache_create("ovl_aio_req", 782 sizeof(struct ovl_aio_req), 783 0, SLAB_HWCACHE_ALIGN, NULL); 784 if (!ovl_aio_request_cachep) 785 return -ENOMEM; 786 787 return 0; 788 } 789 790 void ovl_aio_request_cache_destroy(void) 791 { 792 kmem_cache_destroy(ovl_aio_request_cachep); 793 } 794