| 701 | |
| 702 | #if OFF_MAX <= LONG_MAX |
| 703 | off_t |
| 704 | foffset_lock(struct file *fp, int flags) |
| 705 | { |
| 706 | volatile short *flagsp; |
| 707 | off_t res; |
| 708 | short state; |
| 709 | |
| 710 | KASSERT((flags & FOF_OFFSET) == 0, ("FOF_OFFSET passed")); |
| 711 | |
| 712 | if ((flags & FOF_NOLOCK) != 0) |
| 713 | return (atomic_load_long(&fp->f_offset)); |
| 714 | |
| 715 | /* |
| 716 | * According to McKusick the vn lock was protecting f_offset here. |
| 717 | * It is now protected by the FOFFSET_LOCKED flag. |
| 718 | */ |
| 719 | flagsp = &fp->f_vnread_flags; |
| 720 | if (atomic_cmpset_acq_16(flagsp, 0, FOFFSET_LOCKED)) |
| 721 | return (atomic_load_long(&fp->f_offset)); |
| 722 | |
| 723 | sleepq_lock(&fp->f_vnread_flags); |
| 724 | state = atomic_load_16(flagsp); |
| 725 | for (;;) { |
| 726 | if ((state & FOFFSET_LOCKED) == 0) { |
| 727 | if (!atomic_fcmpset_acq_16(flagsp, &state, |
| 728 | FOFFSET_LOCKED)) |
| 729 | continue; |
| 730 | break; |
| 731 | } |
| 732 | if ((state & FOFFSET_LOCK_WAITING) == 0) { |
| 733 | if (!atomic_fcmpset_acq_16(flagsp, &state, |
| 734 | state | FOFFSET_LOCK_WAITING)) |
| 735 | continue; |
| 736 | } |
| 737 | DROP_GIANT(); |
| 738 | sleepq_add(&fp->f_vnread_flags, NULL, "vofflock", 0, 0); |
| 739 | sleepq_wait(&fp->f_vnread_flags, PUSER -1); |
| 740 | PICKUP_GIANT(); |
| 741 | sleepq_lock(&fp->f_vnread_flags); |
| 742 | state = atomic_load_16(flagsp); |
| 743 | } |
| 744 | res = atomic_load_long(&fp->f_offset); |
| 745 | sleepq_release(&fp->f_vnread_flags); |
| 746 | return (res); |
| 747 | } |
| 748 | |
| 749 | void |
| 750 | foffset_unlock(struct file *fp, off_t val, int flags) |
no test coverage detected