diff options
Diffstat (limited to 'sys')
106 files changed, 2471 insertions, 718 deletions
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 385eb9667652..81427b5b18b6 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -184,6 +184,9 @@ device mrsas # LSI/Avago MegaRAID SAS/SATA, 6Gb/s and 12Gb/s device nvme # base NVMe driver device nvd # expose NVMe namespaces as disks, depends on nvme +# Universal Flash Storage Host Controller Interface support +device ufshci # UFS host controller + # Intel Volume Management Device (VMD) support device vmd @@ -383,6 +386,7 @@ options HID_DEBUG # enable debug msgs device hid # Generic HID support device hidbus # Generic HID Bus options IICHID_SAMPLING # Workaround missing GPIO INTR support +options U2F_MAKE_UHID_ALIAS # install /dev/uhid alias for /dev/u2f/ # EFI devices device efidev # EFI pseudo-device diff --git a/sys/amd64/vmm/io/vioapic.c b/sys/amd64/vmm/io/vioapic.c index 8869dc1383e6..7df6193d6dc0 100644 --- a/sys/amd64/vmm/io/vioapic.c +++ b/sys/amd64/vmm/io/vioapic.c @@ -130,6 +130,15 @@ vioapic_send_intr(struct vioapic *vioapic, int pin) vector = low & IOART_INTVEC; dest = high >> APIC_ID_SHIFT; + /* + * Ideally we'd just call lapic_intr_msi() here with the + * constructed MSI instead of interpreting it for ourselves. + * But until/unless we support emulated IOMMUs with interrupt + * remapping, interpretation is simple. We just need to mask + * in the Extended Destination ID bits for the 15-bit + * enlightenment (http://david.woodhou.se/ExtDestId.pdf) + */ + dest |= ((high & APIC_EXT_ID_MASK) >> APIC_EXT_ID_SHIFT) << 8; vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector); } diff --git a/sys/amd64/vmm/vmm_lapic.c b/sys/amd64/vmm/vmm_lapic.c index fd511733492e..0cae01f172ec 100644 --- a/sys/amd64/vmm/vmm_lapic.c +++ b/sys/amd64/vmm/vmm_lapic.c @@ -115,6 +115,11 @@ lapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg) * physical otherwise. */ dest = (addr >> 12) & 0xff; + /* + * Extended Destination ID support uses bits 5-11 of the address: + * http://david.woodhou.se/ExtDestId.pdf + */ + dest |= ((addr >> 5) & 0x7f) << 8; phys = ((addr & (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG)) != (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG)); delmode = msg & APIC_DELMODE_MASK; diff --git a/sys/amd64/vmm/x86.c b/sys/amd64/vmm/x86.c index 366f1da9f850..2e2224595ab4 100644 --- a/sys/amd64/vmm/x86.c +++ b/sys/amd64/vmm/x86.c @@ -48,7 +48,12 @@ SYSCTL_DECL(_hw_vmm); static SYSCTL_NODE(_hw_vmm, OID_AUTO, topology, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, NULL); -#define CPUID_VM_HIGH 0x40000000 +#define CPUID_VM_SIGNATURE 0x40000000 +#define CPUID_BHYVE_FEATURES 0x40000001 +#define CPUID_VM_HIGH CPUID_BHYVE_FEATURES + +/* Features advertised in CPUID_BHYVE_FEATURES %eax */ +#define CPUID_BHYVE_FEAT_EXT_DEST_ID (1UL << 0) /* MSI Extended Dest ID */ static const char bhyve_id[12] = "bhyve bhyve "; @@ -100,7 +105,7 @@ x86_emulate_cpuid(struct vcpu *vcpu, uint64_t *rax, uint64_t *rbx, if (cpu_exthigh != 0 && func >= 0x80000000) { if (func > cpu_exthigh) func = cpu_exthigh; - } else if (func >= 0x40000000) { + } else if (func >= CPUID_VM_SIGNATURE) { if (func > CPUID_VM_HIGH) func = CPUID_VM_HIGH; } else if (func > cpu_high) { @@ -601,13 +606,20 @@ x86_emulate_cpuid(struct vcpu *vcpu, uint64_t *rax, uint64_t *rbx, regs[3] = 0; break; - case 0x40000000: + case CPUID_VM_SIGNATURE: regs[0] = CPUID_VM_HIGH; bcopy(bhyve_id, ®s[1], 4); bcopy(bhyve_id + 4, ®s[2], 4); bcopy(bhyve_id + 8, ®s[3], 4); break; + case CPUID_BHYVE_FEATURES: + regs[0] = CPUID_BHYVE_FEAT_EXT_DEST_ID; + regs[1] = 0; + regs[2] = 0; + regs[3] = 0; + break; + default: default_leaf: /* diff --git a/sys/arm/arm/pmu_fdt.c b/sys/arm/arm/pmu_fdt.c index 3e733f3e1b18..dd6087652e38 100644 --- a/sys/arm/arm/pmu_fdt.c +++ b/sys/arm/arm/pmu_fdt.c @@ -152,7 +152,7 @@ pmu_parse_intr(device_t dev, struct pmu_softc *sc) if (intr_is_per_cpu(sc->irq[0].res)) { if (has_affinity) { device_printf(dev, - "Per CPU interupt have declared affinity\n"); + "Per CPU interrupt have declared affinity\n"); err = ENXIO; goto done; } @@ -179,7 +179,7 @@ pmu_parse_intr(device_t dev, struct pmu_softc *sc) if (intr_is_per_cpu(sc->irq[i].res)) { - device_printf(dev, "Unexpected per CPU interupt\n"); + device_printf(dev, "Unexpected per CPU interrupt\n"); err = ENXIO; goto done; } diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC index 7394f3842d43..26b0c7bf0294 100644 --- a/sys/arm/conf/GENERIC +++ b/sys/arm/conf/GENERIC @@ -261,6 +261,7 @@ device aw_thermal # Allwinner Thermal Sensor Controller # HID support device hid # Generic HID support device hidbus # Generic HID Bus +options U2F_MAKE_UHID_ALIAS # install /dev/uhid alias for /dev/u2f/ # Flattened Device Tree options FDT # Configure using FDT/DTB data diff --git a/sys/arm64/conf/std.dev b/sys/arm64/conf/std.dev index c5c364ffda04..719f272426dd 100644 --- a/sys/arm64/conf/std.dev +++ b/sys/arm64/conf/std.dev @@ -115,6 +115,7 @@ device mmcsd # mmc/sd flash cards options HID_DEBUG # enable debug msgs device hid # Generic HID support device hidbus # Generic HID Bus +options U2F_MAKE_UHID_ALIAS # install /dev/uhid alias for /dev/u2f/ # Firmware device mmio_sram # Generic on-chip SRAM diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h index 83d964360343..915aeeda3c9e 100644 --- a/sys/cddl/boot/zfs/zfsimpl.h +++ b/sys/cddl/boot/zfs/zfsimpl.h @@ -536,6 +536,12 @@ typedef struct zio_gbh { offsetof(vdev_label_t, vl_uberblock[(n) << VDEV_UBERBLOCK_SHIFT(vd)]) #define VDEV_UBERBLOCK_SIZE(vd) (1ULL << VDEV_UBERBLOCK_SHIFT(vd)) +#define ASHIFT_UBERBLOCK_SHIFT(ashift) \ + MIN(MAX(ashift, UBERBLOCK_SHIFT), \ + MAX_UBERBLOCK_SHIFT) +#define ASHIFT_UBERBLOCK_SIZE(ashift) \ + (1ULL << ASHIFT_UBERBLOCK_SHIFT(ashift)) + typedef struct vdev_phys { char vp_nvlist[VDEV_PHYS_SIZE - sizeof (zio_eck_t)]; zio_eck_t vp_zbt; diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h index 971510ebb6b6..90cd21a80923 100644 --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -83,8 +83,8 @@ /* 76 is obsolete vhangup */ /* 77 is obsolete vlimit */ #define FREEBSD32_SYS_mincore 78 -#define FREEBSD32_SYS_getgroups 79 -#define FREEBSD32_SYS_setgroups 80 +#define FREEBSD32_SYS_freebsd14_getgroups 79 +#define FREEBSD32_SYS_freebsd14_setgroups 80 #define FREEBSD32_SYS_getpgrp 81 #define FREEBSD32_SYS_setpgid 82 #define FREEBSD32_SYS_freebsd32_setitimer 83 @@ -513,4 +513,6 @@ #define FREEBSD32_SYS_exterrctl 592 #define FREEBSD32_SYS_inotify_add_watch_at 593 #define FREEBSD32_SYS_inotify_rm_watch 594 -#define FREEBSD32_SYS_MAXSYSCALL 595 +#define FREEBSD32_SYS_getgroups 595 +#define FREEBSD32_SYS_setgroups 596 +#define FREEBSD32_SYS_MAXSYSCALL 597 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c index 79c414b675b1..f0f8d26554b5 100644 --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -84,8 +84,8 @@ const char *freebsd32_syscallnames[] = { "obs_vhangup", /* 76 = obsolete vhangup */ "obs_vlimit", /* 77 = obsolete vlimit */ "mincore", /* 78 = mincore */ - "getgroups", /* 79 = getgroups */ - "setgroups", /* 80 = setgroups */ + "compat14.getgroups", /* 79 = freebsd14 getgroups */ + "compat14.setgroups", /* 80 = freebsd14 setgroups */ "getpgrp", /* 81 = getpgrp */ "setpgid", /* 82 = setpgid */ "freebsd32_setitimer", /* 83 = freebsd32_setitimer */ @@ -600,4 +600,6 @@ const char *freebsd32_syscallnames[] = { "exterrctl", /* 592 = exterrctl */ "inotify_add_watch_at", /* 593 = inotify_add_watch_at */ "inotify_rm_watch", /* 594 = inotify_rm_watch */ + "getgroups", /* 595 = getgroups */ + "setgroups", /* 596 = setgroups */ }; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c index 1a4b0d87722c..12f1a346c3e9 100644 --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -146,8 +146,8 @@ struct sysent freebsd32_sysent[] = { { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 76 = obsolete vhangup */ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 77 = obsolete vlimit */ { .sy_narg = AS(mincore_args), .sy_call = (sy_call_t *)sys_mincore, .sy_auevent = AUE_MINCORE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 78 = mincore */ - { .sy_narg = AS(getgroups_args), .sy_call = (sy_call_t *)sys_getgroups, .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 79 = getgroups */ - { .sy_narg = AS(setgroups_args), .sy_call = (sy_call_t *)sys_setgroups, .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 80 = setgroups */ + { compat14(AS(freebsd14_getgroups_args),getgroups), .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 79 = freebsd14 getgroups */ + { compat14(AS(freebsd14_setgroups_args),setgroups), .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 80 = freebsd14 setgroups */ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getpgrp, .sy_auevent = AUE_GETPGRP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 81 = getpgrp */ { .sy_narg = AS(setpgid_args), .sy_call = (sy_call_t *)sys_setpgid, .sy_auevent = AUE_SETPGRP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 82 = setpgid */ { .sy_narg = AS(freebsd32_setitimer_args), .sy_call = (sy_call_t *)freebsd32_setitimer, .sy_auevent = AUE_SETITIMER, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 83 = freebsd32_setitimer */ @@ -662,4 +662,6 @@ struct sysent freebsd32_sysent[] = { { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */ { .sy_narg = AS(inotify_add_watch_at_args), .sy_call = (sy_call_t *)sys_inotify_add_watch_at, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 593 = inotify_add_watch_at */ { .sy_narg = AS(inotify_rm_watch_args), .sy_call = (sy_call_t *)sys_inotify_rm_watch, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 594 = inotify_rm_watch */ + { .sy_narg = AS(getgroups_args), .sy_call = (sy_call_t *)sys_getgroups, .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 595 = getgroups */ + { .sy_narg = AS(setgroups_args), .sy_call = (sy_call_t *)sys_setgroups, .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 596 = setgroups */ }; diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c index f9dc514bee7d..e471c5148021 100644 --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -457,22 +457,6 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 3; break; } - /* getgroups */ - case 79: { - struct getgroups_args *p = params; - iarg[a++] = p->gidsetsize; /* int */ - uarg[a++] = (intptr_t)p->gidset; /* gid_t * */ - *n_args = 2; - break; - } - /* setgroups */ - case 80: { - struct setgroups_args *p = params; - iarg[a++] = p->gidsetsize; /* int */ - uarg[a++] = (intptr_t)p->gidset; /* const gid_t * */ - *n_args = 2; - break; - } /* getpgrp */ case 81: { *n_args = 0; @@ -3413,6 +3397,22 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 2; break; } + /* getgroups */ + case 595: { + struct getgroups_args *p = params; + iarg[a++] = p->gidsetsize; /* int */ + uarg[a++] = (intptr_t)p->gidset; /* gid_t * */ + *n_args = 2; + break; + } + /* setgroups */ + case 596: { + struct setgroups_args *p = params; + iarg[a++] = p->gidsetsize; /* int */ + uarg[a++] = (intptr_t)p->gidset; /* const gid_t * */ + *n_args = 2; + break; + } default: *n_args = 0; break; @@ -4112,32 +4112,6 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* getgroups */ - case 79: - switch (ndx) { - case 0: - p = "int"; - break; - case 1: - p = "userland gid_t *"; - break; - default: - break; - }; - break; - /* setgroups */ - case 80: - switch (ndx) { - case 0: - p = "int"; - break; - case 1: - p = "userland const gid_t *"; - break; - default: - break; - }; - break; /* getpgrp */ case 81: break; @@ -9222,6 +9196,32 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* getgroups */ + case 595: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland gid_t *"; + break; + default: + break; + }; + break; + /* setgroups */ + case 596: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland const gid_t *"; + break; + default: + break; + }; + break; default: break; }; @@ -9488,16 +9488,6 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* getgroups */ - case 79: - if (ndx == 0 || ndx == 1) - p = "int"; - break; - /* setgroups */ - case 80: - if (ndx == 0 || ndx == 1) - p = "int"; - break; /* getpgrp */ case 81: /* setpgid */ @@ -11130,6 +11120,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; + /* getgroups */ + case 595: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setgroups */ + case 596: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 2458756ae350..92e98aa57ebf 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2436,7 +2436,7 @@ options HID_DEBUG # enable debug msgs device hidbus # HID bus device hidmap # HID to evdev mapping device hidraw # Raw access driver -options HIDRAW_MAKE_UHID_ALIAS # install /dev/uhid alias +options HIDRAW_MAKE_UHID_ALIAS # install /dev/uhid alias for /dev/hidraw device hconf # Multitouch configuration TLC device hcons # Consumer controls device hgame # Generic game controllers @@ -2446,6 +2446,8 @@ device hmt # HID multitouch (MS-compatible) device hpen # Generic pen driver device hsctrl # System controls device ps4dshock # Sony PS4 DualShock 4 gamepad driver +device u2f # FIDO/U2F authenticator +options U2F_MAKE_UHID_ALIAS # install /dev/uhid alias for /dev/u2f/ device xb360gp # XBox 360 gamepad driver ##################################################################### diff --git a/sys/conf/files b/sys/conf/files index be65ed20d6aa..35318dbc8367 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1750,6 +1750,7 @@ dev/hid/hpen.c optional hpen dev/hid/hsctrl.c optional hsctrl dev/hid/ietp.c optional ietp dev/hid/ps4dshock.c optional ps4dshock +dev/hid/u2f.c optional u2f dev/hid/xb360gp.c optional xb360gp dev/hifn/hifn7751.c optional hifn dev/hptiop/hptiop.c optional hptiop scbus diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index 641001efab5e..45966fea8041 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -178,6 +178,8 @@ crypto/des/des_enc.c optional netsmb crypto/openssl/ossl_aarch64.c optional ossl crypto/openssl/aarch64/chacha-armv8.S optional ossl \ compile-with "${CC} -c ${CFLAGS:N-mgeneral-regs-only} -I$S/crypto/openssl ${WERROR} ${.IMPSRC}" +crypto/openssl/aarch64/chacha-armv8-sve.S optional ossl \ + compile-with "${CC} -c ${CFLAGS:N-mgeneral-regs-only} -I$S/crypto/openssl ${WERROR} ${.IMPSRC}" crypto/openssl/aarch64/poly1305-armv8.S optional ossl \ compile-with "${CC} -c ${CFLAGS:N-mgeneral-regs-only} -I$S/crypto/openssl ${WERROR} ${.IMPSRC}" crypto/openssl/aarch64/sha1-armv8.S optional ossl \ diff --git a/sys/conf/options b/sys/conf/options index a637b0b74a77..bb3d08e88e21 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -1009,6 +1009,7 @@ IICHID_DEBUG opt_hid.h IICHID_SAMPLING opt_hid.h HKBD_DFLT_KEYMAP opt_hkbd.h HIDRAW_MAKE_UHID_ALIAS opt_hid.h +U2F_MAKE_UHID_ALIAS opt_hid.h # kenv options # The early kernel environment (loader environment, config(8)-provided static) diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c index 61d0bb26d1e5..3377db7952ef 100644 --- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c +++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c @@ -494,7 +494,7 @@ zfsctl_common_getattr(vnode_t *vp, vattr_t *vap) vap->va_uid = 0; vap->va_gid = 0; - vap->va_rdev = 0; + vap->va_rdev = NODEV; /* * We are a purely virtual object, so we have no * blocksize or allocated blocks. diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c index 1813c411b013..64995f14ee5f 100644 --- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c @@ -2013,7 +2013,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr) if (vp->v_type == VBLK || vp->v_type == VCHR) vap->va_rdev = zfs_cmpldev(rdev); else - vap->va_rdev = 0; + vap->va_rdev = NODEV; vap->va_gen = zp->z_gen; vap->va_flags = 0; /* FreeBSD: Reset chflags(2) flags. */ vap->va_filerev = zp->z_seq; diff --git a/sys/contrib/openzfs/module/zfs/dsl_deadlist.c b/sys/contrib/openzfs/module/zfs/dsl_deadlist.c index 475db3c89508..41ac72bf1c16 100644 --- a/sys/contrib/openzfs/module/zfs/dsl_deadlist.c +++ b/sys/contrib/openzfs/module/zfs/dsl_deadlist.c @@ -1049,7 +1049,8 @@ dsl_livelist_iterate(void *arg, const blkptr_t *bp, boolean_t bp_freed, ASSERT3U(BP_GET_PSIZE(bp), ==, BP_GET_PSIZE(&found->le_bp)); ASSERT3U(BP_GET_CHECKSUM(bp), ==, BP_GET_CHECKSUM(&found->le_bp)); - ASSERT3U(BP_GET_BIRTH(bp), ==, BP_GET_BIRTH(&found->le_bp)); + ASSERT3U(BP_GET_PHYSICAL_BIRTH(bp), ==, + BP_GET_PHYSICAL_BIRTH(&found->le_bp)); } if (bp_freed) { if (found == NULL) { diff --git a/sys/dev/bnxt/bnxt_re/qplib_res.c b/sys/dev/bnxt/bnxt_re/qplib_res.c index 69661c67708c..f527af031176 100644 --- a/sys/dev/bnxt/bnxt_re/qplib_res.c +++ b/sys/dev/bnxt/bnxt_re/qplib_res.c @@ -875,7 +875,7 @@ int bnxt_qplib_alloc_dpi(struct bnxt_qplib_res *res, dpi->umdbr = umaddr; switch (type) { case BNXT_QPLIB_DPI_TYPE_KERNEL: - /* priviledged dbr was already mapped just initialize it. */ + /* privileged dbr was already mapped just initialize it. */ dpi->umdbr = dpit->ucreg.bar_base + dpit->ucreg.offset + bit_num * PAGE_SIZE; dpi->dbr = dpit->priv_db; @@ -1150,7 +1150,7 @@ int bnxt_qplib_map_db_bar(struct bnxt_qplib_res *res) } ucreg->bar_reg = ioremap(ucreg->bar_base, ucreg->len); if (!ucreg->bar_reg) { - dev_err(&res->pdev->dev, "priviledged dpi map failed!\n"); + dev_err(&res->pdev->dev, "privileged dpi map failed!\n"); return -ENOMEM; } diff --git a/sys/dev/hid/hidbus.c b/sys/dev/hid/hidbus.c index 96d36c8d191d..683449fca49c 100644 --- a/sys/dev/hid/hidbus.c +++ b/sys/dev/hid/hidbus.c @@ -65,7 +65,7 @@ struct hidbus_ivars { struct mtx *mtx; /* child intr mtx */ hid_intr_t *intr_handler; /* executed under mtx*/ void *intr_ctx; - unsigned int refcnt; /* protected by mtx */ + bool active; /* protected by mtx */ struct epoch_context epoch_ctx; CK_STAILQ_ENTRY(hidbus_ivars) link; }; @@ -398,7 +398,7 @@ hidbus_child_detached(device_t bus, device_t child) struct hidbus_softc *sc = device_get_softc(bus); struct hidbus_ivars *tlc = device_get_ivars(child); - KASSERT(tlc->refcnt == 0, ("Child device is running")); + KASSERT(!tlc->active, ("Child device is running")); tlc->mtx = &sc->mtx; tlc->intr_handler = NULL; tlc->flags &= ~HIDBUS_FLAG_CAN_POLL; @@ -423,7 +423,7 @@ hidbus_child_deleted(device_t bus, device_t child) struct hidbus_ivars *tlc = device_get_ivars(child); sx_xlock(&sc->sx); - KASSERT(tlc->refcnt == 0, ("Child device is running")); + KASSERT(!tlc->active, ("Child device is running")); CK_STAILQ_REMOVE(&sc->tlcs, tlc, hidbus_ivars, link); sx_unlock(&sc->sx); epoch_call(INPUT_EPOCH, hidbus_ivar_dtor, &tlc->epoch_ctx); @@ -572,7 +572,7 @@ hidbus_intr(void *context, void *buf, hid_size_t len) if (!HID_IN_POLLING_MODE()) epoch_enter_preempt(INPUT_EPOCH, &et); CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) { - if (tlc->refcnt == 0 || tlc->intr_handler == NULL) + if (!tlc->active || tlc->intr_handler == NULL) continue; if (HID_IN_POLLING_MODE()) { if ((tlc->flags & HIDBUS_FLAG_CAN_POLL) != 0) @@ -602,21 +602,14 @@ hidbus_intr_start(device_t bus, device_t child) MPASS(bus == device_get_parent(child)); struct hidbus_softc *sc = device_get_softc(bus); struct hidbus_ivars *ivar = device_get_ivars(child); - struct hidbus_ivars *tlc; - bool refcnted = false; int error; if (sx_xlock_sig(&sc->sx) != 0) return (EINTR); - CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) { - refcnted |= (tlc->refcnt != 0); - if (tlc == ivar) { - mtx_lock(tlc->mtx); - ++tlc->refcnt; - mtx_unlock(tlc->mtx); - } - } - error = refcnted ? 0 : hid_intr_start(bus); + mtx_lock(ivar->mtx); + ivar->active = true; + mtx_unlock(ivar->mtx); + error = hid_intr_start(bus); sx_unlock(&sc->sx); return (error); @@ -629,21 +622,17 @@ hidbus_intr_stop(device_t bus, device_t child) struct hidbus_softc *sc = device_get_softc(bus); struct hidbus_ivars *ivar = device_get_ivars(child); struct hidbus_ivars *tlc; - bool refcnted = false; + bool active = false; int error; if (sx_xlock_sig(&sc->sx) != 0) return (EINTR); - CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) { - if (tlc == ivar) { - mtx_lock(tlc->mtx); - MPASS(tlc->refcnt != 0); - --tlc->refcnt; - mtx_unlock(tlc->mtx); - } - refcnted |= (tlc->refcnt != 0); - } - error = refcnted ? 0 : hid_intr_stop(bus); + mtx_lock(ivar->mtx); + ivar->active = false; + mtx_unlock(ivar->mtx); + CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) + active |= tlc->active; + error = active ? 0 : hid_intr_stop(bus); sx_unlock(&sc->sx); return (error); diff --git a/sys/dev/hid/hidquirk.h b/sys/dev/hid/hidquirk.h index 4f8b8acbe201..f6fa9f88c6c9 100644 --- a/sys/dev/hid/hidquirk.h +++ b/sys/dev/hid/hidquirk.h @@ -50,6 +50,7 @@ HQ(IS_XBOX360GP), /* device is XBox 360 GamePad */ \ HQ(NOWRITE), /* device does not support writes */ \ HQ(IICHID_SAMPLING), /* IIC backend runs in sampling mode */ \ + HQ(NO_READAHEAD), /* Disable interrupt after one report */\ \ /* Various quirks */ \ HQ(HID_IGNORE), /* device should be ignored by hid class */ \ diff --git a/sys/dev/hid/hidraw.c b/sys/dev/hid/hidraw.c index 06f70070f61b..4855843cd265 100644 --- a/sys/dev/hid/hidraw.c +++ b/sys/dev/hid/hidraw.c @@ -85,6 +85,12 @@ SYSCTL_INT(_hw_hid_hidraw, OID_AUTO, debug, CTLFLAG_RWTUN, free((buf), M_DEVBUF); \ } +#ifdef HIDRAW_MAKE_UHID_ALIAS +#define HIDRAW_NAME "uhid" +#else +#define HIDRAW_NAME "hidraw" +#endif + struct hidraw_softc { device_t sc_dev; /* base device */ @@ -183,8 +189,8 @@ hidraw_identify(driver_t *driver, device_t parent) { device_t child; - if (device_find_child(parent, "hidraw", DEVICE_UNIT_ANY) == NULL) { - child = BUS_ADD_CHILD(parent, 0, "hidraw", + if (device_find_child(parent, HIDRAW_NAME, DEVICE_UNIT_ANY) == NULL) { + child = BUS_ADD_CHILD(parent, 0, HIDRAW_NAME, device_get_unit(parent)); if (child != NULL) hidbus_set_index(child, HIDRAW_INDEX); @@ -1050,7 +1056,7 @@ static device_method_t hidraw_methods[] = { }; static driver_t hidraw_driver = { - "hidraw", + HIDRAW_NAME, hidraw_methods, sizeof(struct hidraw_softc) }; diff --git a/sys/dev/hid/ietp.c b/sys/dev/hid/ietp.c index 217585a7948b..73a5cb7414d4 100644 --- a/sys/dev/hid/ietp.c +++ b/sys/dev/hid/ietp.c @@ -102,6 +102,7 @@ struct ietp_softc { device_t dev; struct evdev_dev *evdev; + bool open; uint8_t report_id; hid_size_t report_len; @@ -217,13 +218,25 @@ static const struct evdev_methods ietp_evdev_methods = { static int ietp_ev_open(struct evdev_dev *evdev) { - return (hid_intr_start(evdev_get_softc(evdev))); + struct ietp_softc *sc = evdev_get_softc(evdev); + int error; + + error = hid_intr_start(sc->dev); + if (error == 0) + sc->open = true; + return (error); } static int ietp_ev_close(struct evdev_dev *evdev) { - return (hid_intr_stop(evdev_get_softc(evdev))); + struct ietp_softc *sc = evdev_get_softc(evdev); + int error; + + error = hid_intr_stop(sc->dev); + if (error == 0) + sc->open = false; + return (error); } static int @@ -275,7 +288,7 @@ ietp_attach(struct ietp_softc *sc) evdev_set_id(sc->evdev, hw->idBus, hw->idVendor, hw->idProduct, hw->idVersion); evdev_set_serial(sc->evdev, hw->serial); - evdev_set_methods(sc->evdev, sc->dev, &ietp_evdev_methods); + evdev_set_methods(sc->evdev, sc, &ietp_evdev_methods); evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT); evdev_set_flag(sc->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */ @@ -584,11 +597,13 @@ ietp_iic_set_absolute_mode(device_t dev, bool enable) * Some ASUS touchpads need to be powered on to enter absolute mode. */ require_wakeup = false; - for (i = 0; i < nitems(special_fw); i++) { - if (sc->ic_type == special_fw[i].ic_type && - sc->product_id == special_fw[i].product_id) { - require_wakeup = true; - break; + if (!sc->open) { + for (i = 0; i < nitems(special_fw); i++) { + if (sc->ic_type == special_fw[i].ic_type && + sc->product_id == special_fw[i].product_id) { + require_wakeup = true; + break; + } } } diff --git a/sys/dev/hid/u2f.c b/sys/dev/hid/u2f.c new file mode 100644 index 000000000000..ac2eba7a499d --- /dev/null +++ b/sys/dev/hid/u2f.c @@ -0,0 +1,590 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022-2023 Vladimir Kondratyev <wulf@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_hid.h" + +#include <sys/param.h> +#ifdef COMPAT_FREEBSD32 +#include <sys/abi_compat.h> +#endif +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/fcntl.h> +#include <sys/filio.h> +#include <sys/ioccom.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/poll.h> +#include <sys/priv.h> +#include <sys/proc.h> +#include <sys/selinfo.h> +#include <sys/sysctl.h> +#include <sys/systm.h> +#include <sys/uio.h> + +#include <dev/evdev/input.h> + +#define HID_DEBUG_VAR u2f_debug +#include <dev/hid/hid.h> +#include <dev/hid/hidbus.h> +#include <dev/hid/hidquirk.h> + +#include <dev/usb/usb_ioctl.h> + +#ifdef HID_DEBUG +static int u2f_debug = 0; +static SYSCTL_NODE(_hw_hid, OID_AUTO, u2f, CTLFLAG_RW, 0, + "FIDO/U2F authenticator"); +SYSCTL_INT(_hw_hid_u2f, OID_AUTO, debug, CTLFLAG_RWTUN, + &u2f_debug, 0, "Debug level"); +#endif + +#define U2F_MAX_REPORT_SIZE 64 + +/* A match on these entries will load u2f */ +static const struct hid_device_id u2f_devs[] = { + { HID_BUS(BUS_USB), HID_TLC(HUP_FIDO, HUF_U2FHID) }, +}; + +struct u2f_softc { + device_t sc_dev; /* base device */ + struct cdev *dev; + + struct mtx sc_mtx; /* hidbus private mutex */ + void *sc_rdesc; + hid_size_t sc_rdesc_size; + hid_size_t sc_isize; + hid_size_t sc_osize; + struct selinfo sc_rsel; + struct { /* driver state */ + bool open:1; /* device is open */ + bool aslp:1; /* waiting for device data in read() */ + bool sel:1; /* waiting for device data in poll() */ + bool data:1; /* input report is stored in sc_buf */ + int reserved:28; + } sc_state; + int sc_fflags; /* access mode for open lifetime */ + + uint8_t sc_buf[U2F_MAX_REPORT_SIZE]; +}; + +static d_open_t u2f_open; +static d_read_t u2f_read; +static d_write_t u2f_write; +static d_ioctl_t u2f_ioctl; +static d_poll_t u2f_poll; +static d_kqfilter_t u2f_kqfilter; + +static d_priv_dtor_t u2f_dtor; + +static struct cdevsw u2f_cdevsw = { + .d_version = D_VERSION, + .d_open = u2f_open, + .d_read = u2f_read, + .d_write = u2f_write, + .d_ioctl = u2f_ioctl, + .d_poll = u2f_poll, + .d_kqfilter = u2f_kqfilter, + .d_name = "u2f", +}; + +static hid_intr_t u2f_intr; + +static device_probe_t u2f_probe; +static device_attach_t u2f_attach; +static device_detach_t u2f_detach; + +static int u2f_kqread(struct knote *, long); +static void u2f_kqdetach(struct knote *); +static void u2f_notify(struct u2f_softc *); + +static struct filterops u2f_filterops_read = { + .f_isfd = 1, + .f_detach = u2f_kqdetach, + .f_event = u2f_kqread, +}; + +static int +u2f_probe(device_t dev) +{ + int error; + + error = HIDBUS_LOOKUP_DRIVER_INFO(dev, u2f_devs); + if (error != 0) + return (error); + + hidbus_set_desc(dev, "Authenticator"); + + return (BUS_PROBE_GENERIC); +} + +static int +u2f_attach(device_t dev) +{ + struct u2f_softc *sc = device_get_softc(dev); + struct hid_device_info *hw = __DECONST(struct hid_device_info *, + hid_get_device_info(dev)); + struct make_dev_args mda; + int error; + + sc->sc_dev = dev; + + error = hid_get_report_descr(dev, &sc->sc_rdesc, &sc->sc_rdesc_size); + if (error != 0) + return (ENXIO); + sc->sc_isize = hid_report_size_max(sc->sc_rdesc, sc->sc_rdesc_size, + hid_input, NULL); + if (sc->sc_isize > U2F_MAX_REPORT_SIZE) { + device_printf(dev, "Input report size too large. Truncate.\n"); + sc->sc_isize = U2F_MAX_REPORT_SIZE; + } + sc->sc_osize = hid_report_size_max(sc->sc_rdesc, sc->sc_rdesc_size, + hid_output, NULL); + if (sc->sc_osize > U2F_MAX_REPORT_SIZE) { + device_printf(dev, "Output report size too large. Truncate.\n"); + sc->sc_osize = U2F_MAX_REPORT_SIZE; + } + + mtx_init(&sc->sc_mtx, "u2f lock", NULL, MTX_DEF); + knlist_init_mtx(&sc->sc_rsel.si_note, &sc->sc_mtx); + + make_dev_args_init(&mda); + mda.mda_flags = MAKEDEV_WAITOK; + mda.mda_devsw = &u2f_cdevsw; + mda.mda_uid = UID_ROOT; + mda.mda_gid = GID_U2F; + mda.mda_mode = 0660; + mda.mda_si_drv1 = sc; + + error = make_dev_s(&mda, &sc->dev, "u2f/%d", device_get_unit(dev)); + if (error) { + device_printf(dev, "Can not create character device\n"); + u2f_detach(dev); + return (error); + } +#ifdef U2F_MAKE_UHID_ALIAS + (void)make_dev_alias(sc->dev, "uhid%d", device_get_unit(dev)); +#endif + + hid_add_dynamic_quirk(hw, HQ_NO_READAHEAD); + + hidbus_set_lock(dev, &sc->sc_mtx); + hidbus_set_intr(dev, u2f_intr, sc); + + return (0); +} + +static int +u2f_detach(device_t dev) +{ + struct u2f_softc *sc = device_get_softc(dev); + + DPRINTF("sc=%p\n", sc); + + if (sc->dev != NULL) { + mtx_lock(&sc->sc_mtx); + sc->dev->si_drv1 = NULL; + /* Wake everyone */ + u2f_notify(sc); + mtx_unlock(&sc->sc_mtx); + destroy_dev(sc->dev); + } + + hid_intr_stop(sc->sc_dev); + + knlist_clear(&sc->sc_rsel.si_note, 0); + knlist_destroy(&sc->sc_rsel.si_note); + seldrain(&sc->sc_rsel); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +void +u2f_intr(void *context, void *buf, hid_size_t len) +{ + struct u2f_softc *sc = context; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + DPRINTFN(5, "len=%d\n", len); + DPRINTFN(5, "data = %*D\n", len, buf, " "); + + if (sc->sc_state.data) + return; + + if (len > sc->sc_isize) + len = sc->sc_isize; + + bcopy(buf, sc->sc_buf, len); + + /* Make sure we don't process old data */ + if (len < sc->sc_isize) + bzero(sc->sc_buf + len, sc->sc_isize - len); + + sc->sc_state.data = true; + + u2f_notify(sc); +} + +static int +u2f_open(struct cdev *dev, int flag, int mode, struct thread *td) +{ + struct u2f_softc *sc = dev->si_drv1; + int error; + + if (sc == NULL) + return (ENXIO); + + DPRINTF("sc=%p\n", sc); + + mtx_lock(&sc->sc_mtx); + if (sc->sc_state.open) { + mtx_unlock(&sc->sc_mtx); + return (EBUSY); + } + sc->sc_state.open = true; + mtx_unlock(&sc->sc_mtx); + + error = devfs_set_cdevpriv(sc, u2f_dtor); + if (error != 0) { + mtx_lock(&sc->sc_mtx); + sc->sc_state.open = false; + mtx_unlock(&sc->sc_mtx); + return (error); + } + + /* Set up interrupt pipe. */ + sc->sc_state.data = false; + sc->sc_fflags = flag; + + return (0); +} + + +static void +u2f_dtor(void *data) +{ + struct u2f_softc *sc = data; + +#ifdef NOT_YET + /* Disable interrupts. */ + hid_intr_stop(sc->sc_dev); +#endif + + mtx_lock(&sc->sc_mtx); + sc->sc_state.open = false; + mtx_unlock(&sc->sc_mtx); +} + +static int +u2f_read(struct cdev *dev, struct uio *uio, int flag) +{ + uint8_t buf[U2F_MAX_REPORT_SIZE]; + struct u2f_softc *sc = dev->si_drv1; + size_t length = 0; + int error; + + DPRINTFN(1, "\n"); + + if (sc == NULL) + return (EIO); + + if (!sc->sc_state.data) + hid_intr_start(sc->sc_dev); + + mtx_lock(&sc->sc_mtx); + if (dev->si_drv1 == NULL) { + error = EIO; + goto exit; + } + + while (!sc->sc_state.data) { + if (flag & O_NONBLOCK) { + error = EWOULDBLOCK; + goto exit; + } + sc->sc_state.aslp = true; + DPRINTFN(5, "sleep on %p\n", &sc->sc_buf); + error = mtx_sleep(&sc->sc_buf, &sc->sc_mtx, PZERO | PCATCH, + "u2frd", 0); + DPRINTFN(5, "woke, error=%d\n", error); + if (dev->si_drv1 == NULL) + error = EIO; + if (error) { + sc->sc_state.aslp = false; + goto exit; + } + } + + if (sc->sc_state.data && uio->uio_resid > 0) { + length = min(uio->uio_resid, sc->sc_isize); + memcpy(buf, sc->sc_buf, length); + sc->sc_state.data = false; + } +exit: + mtx_unlock(&sc->sc_mtx); + if (length != 0) { + /* Copy the data to the user process. */ + DPRINTFN(5, "got %lu chars\n", (u_long)length); + error = uiomove(buf, length, uio); + } + + return (error); +} + +static int +u2f_write(struct cdev *dev, struct uio *uio, int flag) +{ + uint8_t buf[U2F_MAX_REPORT_SIZE]; + struct u2f_softc *sc = dev->si_drv1; + int error; + + DPRINTFN(1, "\n"); + + if (sc == NULL) + return (EIO); + + if (uio->uio_resid != sc->sc_osize) + return (EINVAL); + error = uiomove(buf, uio->uio_resid, uio); + if (error == 0) + error = hid_write(sc->sc_dev, buf, sc->sc_osize); + + return (error); +} + +#ifdef COMPAT_FREEBSD32 +static void +update_ugd32(const struct usb_gen_descriptor *ugd, + struct usb_gen_descriptor32 *ugd32) +{ + /* Don't update hgd_data pointer */ + CP(*ugd, *ugd32, ugd_lang_id); + CP(*ugd, *ugd32, ugd_maxlen); + CP(*ugd, *ugd32, ugd_actlen); + CP(*ugd, *ugd32, ugd_offset); + CP(*ugd, *ugd32, ugd_config_index); + CP(*ugd, *ugd32, ugd_string_index); + CP(*ugd, *ugd32, ugd_iface_index); + CP(*ugd, *ugd32, ugd_altif_index); + CP(*ugd, *ugd32, ugd_endpt_index); + CP(*ugd, *ugd32, ugd_report_type); + /* Don't update reserved */ +} +#endif + +static int +u2f_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, + struct thread *td) +{ +#ifdef COMPAT_FREEBSD32 + struct usb_gen_descriptor local_ugd; + struct usb_gen_descriptor32 *ugd32 = NULL; +#endif + struct u2f_softc *sc = dev->si_drv1; + struct usb_gen_descriptor *ugd = (struct usb_gen_descriptor *)addr; + uint32_t size; + + DPRINTFN(2, "cmd=%lx\n", cmd); + + if (sc == NULL) + return (EIO); + +#ifdef COMPAT_FREEBSD32 + switch (cmd) { + case USB_GET_REPORT_DESC32: + cmd = _IOC_NEWTYPE(cmd, struct usb_gen_descriptor); + ugd32 = (struct usb_gen_descriptor32 *)addr; + ugd = &local_ugd; + PTRIN_CP(*ugd32, *ugd, ugd_data); + CP(*ugd32, *ugd, ugd_lang_id); + CP(*ugd32, *ugd, ugd_maxlen); + CP(*ugd32, *ugd, ugd_actlen); + CP(*ugd32, *ugd, ugd_offset); + CP(*ugd32, *ugd, ugd_config_index); + CP(*ugd32, *ugd, ugd_string_index); + CP(*ugd32, *ugd, ugd_iface_index); + CP(*ugd32, *ugd, ugd_altif_index); + CP(*ugd32, *ugd, ugd_endpt_index); + CP(*ugd32, *ugd, ugd_report_type); + /* Don't copy reserved */ + break; + } +#endif + + /* fixed-length ioctls handling */ + switch (cmd) { + case FIONBIO: + /* All handled in the upper FS layer. */ + return (0); + + case USB_GET_REPORT_DESC: + size = MIN(sc->sc_rdesc_size, ugd->ugd_maxlen); + ugd->ugd_actlen = size; +#ifdef COMPAT_FREEBSD32 + if (ugd32 != NULL) + update_ugd32(ugd, ugd32); +#endif + if (ugd->ugd_data == NULL) + return (0); /* descriptor length only */ + + return (copyout(sc->sc_rdesc, ugd->ugd_data, size)); + + case USB_GET_DEVICEINFO: + return(hid_ioctl( + sc->sc_dev, USB_GET_DEVICEINFO, (uintptr_t)addr)); + } + + return (EINVAL); +} + +static int +u2f_poll(struct cdev *dev, int events, struct thread *td) +{ + struct u2f_softc *sc = dev->si_drv1; + int revents = 0; + bool start_intr = false; + + if (sc == NULL) + return (POLLHUP); + + if (events & (POLLOUT | POLLWRNORM) && (sc->sc_fflags & FWRITE)) + revents |= events & (POLLOUT | POLLWRNORM); + if (events & (POLLIN | POLLRDNORM) && (sc->sc_fflags & FREAD)) { + mtx_lock(&sc->sc_mtx); + if (sc->sc_state.data) + revents |= events & (POLLIN | POLLRDNORM); + else { + sc->sc_state.sel = true; + start_intr = true; + selrecord(td, &sc->sc_rsel); + } + mtx_unlock(&sc->sc_mtx); + if (start_intr) + hid_intr_start(sc->sc_dev); + } + + return (revents); +} + +static int +u2f_kqfilter(struct cdev *dev, struct knote *kn) +{ + struct u2f_softc *sc = dev->si_drv1; + + if (sc == NULL) + return (ENXIO); + + switch(kn->kn_filter) { + case EVFILT_READ: + if (sc->sc_fflags & FREAD) { + kn->kn_fop = &u2f_filterops_read; + break; + } + /* FALLTHROUGH */ + default: + return(EINVAL); + } + kn->kn_hook = sc; + + knlist_add(&sc->sc_rsel.si_note, kn, 0); + return (0); +} + +static int +u2f_kqread(struct knote *kn, long hint) +{ + struct u2f_softc *sc = kn->kn_hook; + int ret; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (sc->dev->si_drv1 == NULL) { + kn->kn_flags |= EV_EOF; + ret = 1; + } else { + ret = sc->sc_state.data ? 1 : 0; + if (!sc->sc_state.data) + hid_intr_start(sc->sc_dev); + } + + return (ret); +} + +static void +u2f_kqdetach(struct knote *kn) +{ + struct u2f_softc *sc = kn->kn_hook; + + knlist_remove(&sc->sc_rsel.si_note, kn, 0); +} + +static void +u2f_notify(struct u2f_softc *sc) +{ + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (sc->sc_state.aslp) { + sc->sc_state.aslp = false; + DPRINTFN(5, "waking %p\n", &sc->sc_buf); + wakeup(&sc->sc_buf); + } + if (sc->sc_state.sel) { + sc->sc_state.sel = false; + selwakeuppri(&sc->sc_rsel, PZERO); + } + KNOTE_LOCKED(&sc->sc_rsel.si_note, 0); +} + +static device_method_t u2f_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, u2f_probe), + DEVMETHOD(device_attach, u2f_attach), + DEVMETHOD(device_detach, u2f_detach), + + DEVMETHOD_END +}; + +static driver_t u2f_driver = { +#ifdef U2F_MAKE_UHID_ALIAS + "uhid", +#else + "u2f", +#endif + u2f_methods, + sizeof(struct u2f_softc) +}; + +DRIVER_MODULE(u2f, hidbus, u2f_driver, NULL, NULL); +MODULE_DEPEND(u2f, hidbus, 1, 1, 1); +MODULE_DEPEND(u2f, hid, 1, 1, 1); +MODULE_VERSION(u2f, 1); +HID_PNP_INFO(u2f_devs); diff --git a/sys/dev/ice/ice_bitops.h b/sys/dev/ice/ice_bitops.h index c480900596f4..a623f810c101 100644 --- a/sys/dev/ice/ice_bitops.h +++ b/sys/dev/ice/ice_bitops.h @@ -198,7 +198,7 @@ static inline void ice_zero_bitmap(ice_bitmap_t *bmp, u16 size) * ice_and_bitmap - bitwise AND 2 bitmaps and store result in dst bitmap * @dst: Destination bitmap that receive the result of the operation * @bmp1: The first bitmap to intersect - * @bmp2: The second bitmap to intersect wit the first + * @bmp2: The second bitmap to intersect with the first * @size: Size of the bitmaps in bits * * This function performs a bitwise AND on two "source" bitmaps of the same size @@ -237,7 +237,7 @@ ice_and_bitmap(ice_bitmap_t *dst, const ice_bitmap_t *bmp1, * ice_or_bitmap - bitwise OR 2 bitmaps and store result in dst bitmap * @dst: Destination bitmap that receive the result of the operation * @bmp1: The first bitmap to intersect - * @bmp2: The second bitmap to intersect wit the first + * @bmp2: The second bitmap to intersect with the first * @size: Size of the bitmaps in bits * * This function performs a bitwise OR on two "source" bitmaps of the same size diff --git a/sys/dev/ice/ice_lan_tx_rx.h b/sys/dev/ice/ice_lan_tx_rx.h index 693e0ca5efc6..eedacdab0216 100644 --- a/sys/dev/ice/ice_lan_tx_rx.h +++ b/sys/dev/ice/ice_lan_tx_rx.h @@ -630,7 +630,7 @@ enum ice_rxdid { ICE_RXDID_LAST = 63, }; -/* Recceive Flex descriptor Dword Index */ +/* Receive Flex descriptor Dword Index */ enum ice_flex_word { ICE_RX_FLEX_DWORD_0 = 0, ICE_RX_FLEX_DWORD_1, diff --git a/sys/dev/ice/ice_lib.h b/sys/dev/ice/ice_lib.h index 308b2bda2790..640bdf8fed7b 100644 --- a/sys/dev/ice/ice_lib.h +++ b/sys/dev/ice/ice_lib.h @@ -313,7 +313,7 @@ enum ice_dyn_idx_t { ICE_ITR_NONE = 3 /* ITR_NONE must not be used as an index */ }; -/* By convenction ITR0 is used for RX, and ITR1 is used for TX */ +/* By convention ITR0 is used for RX, and ITR1 is used for TX */ #define ICE_RX_ITR ICE_IDX_ITR0 #define ICE_TX_ITR ICE_IDX_ITR1 diff --git a/sys/dev/ice/ice_protocol_type.h b/sys/dev/ice/ice_protocol_type.h index 300d61bfb5d9..b90c25e6c427 100644 --- a/sys/dev/ice/ice_protocol_type.h +++ b/sys/dev/ice/ice_protocol_type.h @@ -143,7 +143,7 @@ enum ice_prot_id { ICE_PROT_LLDP_OF = 117, ICE_PROT_ARP_OF = 118, ICE_PROT_EAPOL_OF = 120, - ICE_PROT_META_ID = 255, /* when offset == metaddata */ + ICE_PROT_META_ID = 255, /* when offset == metadata */ ICE_PROT_INVALID = 255 /* when offset == ICE_FV_OFFSET_INVAL */ }; diff --git a/sys/dev/iicbus/gpio/pcf8574.c b/sys/dev/iicbus/gpio/pcf8574.c index 86c78ffb15e6..bf60dec67557 100644 --- a/sys/dev/iicbus/gpio/pcf8574.c +++ b/sys/dev/iicbus/gpio/pcf8574.c @@ -159,9 +159,7 @@ pcf8574_detach(device_t dev) sc = device_get_softc(dev); - if (sc->busdev != NULL) - gpiobus_detach_bus(sc->busdev); - + gpiobus_detach_bus(dev); sx_destroy(&sc->lock); return (0); } diff --git a/sys/dev/iicbus/gpio/tca64xx.c b/sys/dev/iicbus/gpio/tca64xx.c index a973ef22f3fa..ab8fedd3f8fd 100644 --- a/sys/dev/iicbus/gpio/tca64xx.c +++ b/sys/dev/iicbus/gpio/tca64xx.c @@ -292,9 +292,7 @@ tca64xx_detach(device_t dev) sc = device_get_softc(dev); - if (sc->busdev != NULL) - gpiobus_detach_bus(sc->busdev); - + gpiobus_detach_bus(dev); mtx_destroy(&sc->mtx); return (0); diff --git a/sys/dev/iicbus/iichid.c b/sys/dev/iicbus/iichid.c index 3f1d7a0cefba..fdb4816b8bd9 100644 --- a/sys/dev/iicbus/iichid.c +++ b/sys/dev/iicbus/iichid.c @@ -861,7 +861,8 @@ iichid_intr_start(device_t dev, device_t child __unused) sc = device_get_softc(dev); DPRINTF(sc, "iichid device open\n"); - iichid_set_power_state(sc, IICHID_PS_ON, IICHID_PS_NULL); + if (!sc->open) + iichid_set_power_state(sc, IICHID_PS_ON, IICHID_PS_NULL); return (0); } diff --git a/sys/dev/isci/scil/intel_sata.h b/sys/dev/isci/scil/intel_sata.h index 4cf4adf03e07..fdad5be9b083 100644 --- a/sys/dev/isci/scil/intel_sata.h +++ b/sys/dev/isci/scil/intel_sata.h @@ -61,7 +61,7 @@ * * @brief This file defines all of the SATA releated constants, enumerations, * and types. Please note that this file does not necessarily contain - * an exhaustive list of all contants and commands. + * an exhaustive list of all constants and commands. */ /** diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c b/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c index 6e24395b5577..c45f02cdaf42 100644 --- a/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c +++ b/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c @@ -1783,8 +1783,8 @@ mlx5e_add_vxlan_rule(struct mlx5e_priv *priv, sa_family_t family, u_int port) el->refcount++; if (el->installed) return (0); - } - el = mlx5e_vxlan_alloc_db_el(priv, proto, port); + } else + el = mlx5e_vxlan_alloc_db_el(priv, proto, port); if ((if_getcapenable(priv->ifp) & IFCAP_VXLAN_HWCSUM) != 0) { err = mlx5e_add_vxlan_rule_from_db(priv, el); diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c index 56db0b26487b..c38d50e54ad8 100644 --- a/sys/dev/uart/uart_dev_ns8250.c +++ b/sys/dev/uart/uart_dev_ns8250.c @@ -495,6 +495,7 @@ UART_CLASS(uart_ns8250_class); static struct acpi_spcr_compat_data acpi_spcr_compat_data[] = { { &uart_ns8250_class, ACPI_DBG2_16550_COMPATIBLE }, { &uart_ns8250_class, ACPI_DBG2_16550_SUBSET }, + { &uart_ns8250_class, ACPI_DBG2_16550_WITH_GAS }, { NULL, 0 }, }; UART_ACPI_SPCR_CLASS(acpi_spcr_compat_data); diff --git a/sys/dev/ufshci/ufshci.h b/sys/dev/ufshci/ufshci.h index 9f0faaadeb57..b96d82ff836e 100644 --- a/sys/dev/ufshci/ufshci.h +++ b/sys/dev/ufshci/ufshci.h @@ -160,19 +160,19 @@ enum ufshci_data_direction { UFSHCI_DATA_DIRECTION_RESERVED = 0b11, }; -enum ufshci_overall_command_status { - UFSHCI_OCS_SUCCESS = 0x0, - UFSHCI_OCS_INVALID_COMMAND_TABLE_ATTRIBUTES = 0x01, - UFSHCI_OCS_INVALID_PRDT_ATTRIBUTES = 0x02, - UFSHCI_OCS_MISMATCH_DATA_BUFFER_SIZE = 0x03, - UFSHCI_OCS_MISMATCH_RESPONSE_UPIU_SIZE = 0x04, - UFSHCI_OCS_COMMUNICATION_FAILURE_WITHIN_UIC_LAYERS = 0x05, - UFSHCI_OCS_ABORTED = 0x06, - UFSHCI_OCS_HOST_CONTROLLER_FATAL_ERROR = 0x07, - UFSHCI_OCS_DEVICE_FATAL_ERROR = 0x08, - UFSHCI_OCS_INVALID_CRYPTO_CONFIGURATION = 0x09, - UFSHCI_OCS_GENERAL_CRYPTO_ERROR = 0x0A, - UFSHCI_OCS_INVALID = 0xF, +enum ufshci_utr_overall_command_status { + UFSHCI_UTR_OCS_SUCCESS = 0x0, + UFSHCI_UTR_OCS_INVALID_COMMAND_TABLE_ATTRIBUTES = 0x01, + UFSHCI_UTR_OCS_INVALID_PRDT_ATTRIBUTES = 0x02, + UFSHCI_UTR_OCS_MISMATCH_DATA_BUFFER_SIZE = 0x03, + UFSHCI_UTR_OCS_MISMATCH_RESPONSE_UPIU_SIZE = 0x04, + UFSHCI_UTR_OCS_COMMUNICATION_FAILURE_WITHIN_UIC_LAYERS = 0x05, + UFSHCI_UTR_OCS_ABORTED = 0x06, + UFSHCI_UTR_OCS_HOST_CONTROLLER_FATAL_ERROR = 0x07, + UFSHCI_UTR_OCS_DEVICE_FATAL_ERROR = 0x08, + UFSHCI_UTR_OCS_INVALID_CRYPTO_CONFIGURATION = 0x09, + UFSHCI_UTR_OCS_GENERAL_CRYPTO_ERROR = 0x0A, + UFSHCI_UTR_OCS_INVALID = 0xF, }; struct ufshci_utp_xfer_req_desc { @@ -271,6 +271,18 @@ _Static_assert(sizeof(struct ufshci_utp_cmd_desc) == #define UFSHCI_UTP_TASK_MGMT_REQ_SIZE 32 #define UFSHCI_UTP_TASK_MGMT_RESP_SIZE 32 +enum ufshci_utmr_overall_command_status { + UFSHCI_UTMR_OCS_SUCCESS = 0x0, + UFSHCI_UTMR_OCS_INVALID_TASK_MANAGEMENT_FUNCTION_ATTRIBUTES = 0x01, + UFSHCI_UTMR_OCS_MISMATCH_TASK_MANAGEMENT_REQUEST_SIZE = 0x02, + UFSHCI_UTMR_OCS_MISMATCH_TASK_MANAGEMENT_RESPONSE_SIZE = 0x03, + UFSHCI_UTMR_OCS_PEER_COMMUNICATION_FAILURE = 0x04, + UFSHCI_UTMR_OCS_ABORTED = 0x05, + UFSHCI_UTMR_OCS_FATAL_ERROR = 0x06, + UFSHCI_UTMR_OCS_DEVICE_FATAL_ERROR = 0x07, + UFSHCI_UTMR_OCS_INVALID = 0xF, +}; + /* UFSHCI spec 4.1, section 6.3.1 "UTP Task Management Request Descriptor" */ struct ufshci_utp_task_mgmt_req_desc { /* dword 0 */ @@ -356,6 +368,7 @@ struct ufshci_upiu { _Static_assert(sizeof(struct ufshci_upiu) == 512, "ufshci_upiu must be 512 bytes"); +/* UFS Spec 4.1, section 10.7.1 "COMMAND UPIU" */ struct ufshci_cmd_command_upiu { /* dword 0-2 */ struct ufshci_upiu_header header; @@ -376,6 +389,7 @@ _Static_assert(sizeof(struct ufshci_cmd_command_upiu) % UFSHCI_UPIU_ALIGNMENT == 0, "UPIU requires 64-bit alignment"); +/* UFS Spec 4.1, section 10.7.2 "RESPONSE UPIU" */ struct ufshci_cmd_response_upiu { /* dword 0-2 */ struct ufshci_upiu_header header; @@ -403,6 +417,69 @@ _Static_assert(sizeof(struct ufshci_cmd_response_upiu) % 0, "UPIU requires 64-bit alignment"); +enum task_management_function { + UFSHCI_TASK_MGMT_FUNCTION_ABORT_TASK = 0x01, + UFSHCI_TASK_MGMT_FUNCTION_ABORT_TASK_SET = 0x02, + UFSHCI_TASK_MGMT_FUNCTION_CLEAR_TASK_SET = 0x04, + UFSHCI_TASK_MGMT_FUNCTION_LOGICAL_UNIT_RESET = 0x08, + UFSHCI_TASK_MGMT_FUNCTION_QUERY_TASK = 0x80, + UFSHCI_TASK_MGMT_FUNCTION_QUERY_TASKSET = 0x81, +}; + +/* UFS Spec 4.1, section 10.7.6 "TASK MANAGEMENT REQUEST UPIU" */ +struct ufshci_task_mgmt_request_upiu { + /* dword 0-2 */ + struct ufshci_upiu_header header; + /* dword 3 */ + uint32_t input_param1; /* (Big-endian) */ + /* dword 4 */ + uint32_t input_param2; /* (Big-endian) */ + /* dword 5 */ + uint32_t input_param3; /* (Big-endian) */ + /* dword 6-7 */ + uint8_t reserved[8]; +} __packed __aligned(4); + +_Static_assert(sizeof(struct ufshci_task_mgmt_request_upiu) == 32, + "bad size for ufshci_task_mgmt_request_upiu"); +_Static_assert(sizeof(struct ufshci_task_mgmt_request_upiu) <= + UFSHCI_UTP_XFER_RESP_SIZE, + "bad size for ufshci_task_mgmt_request_upiu"); +_Static_assert(sizeof(struct ufshci_task_mgmt_request_upiu) % + UFSHCI_UPIU_ALIGNMENT == + 0, + "UPIU requires 64-bit alignment"); + +enum task_management_service_response { + UFSHCI_TASK_MGMT_SERVICE_RESPONSE_FUNCTION_COMPLETE = 0x00, + UFSHCI_TASK_MGMT_SERVICE_RESPONSE_FUNCTION_NOT_SUPPORTED = 0x04, + UFSHCI_TASK_MGMT_SERVICE_RESPONSE_FUNCTION_FAILED = 0x05, + UFSHCI_TASK_MGMT_SERVICE_RESPONSE_FUNCTION_SUCCEEDED = 0x08, + UFSHCI_TASK_MGMT_SERVICE_RESPONSE_INCORRECT_LUN = 0x09, +}; + +/* UFS Spec 4.1, section 10.7.7 "TASK MANAGEMENT RESPONSE UPIU" */ +struct ufshci_task_mgmt_response_upiu { + /* dword 0-2 */ + struct ufshci_upiu_header header; + /* dword 3 */ + uint32_t output_param1; /* (Big-endian) */ + /* dword 4 */ + uint32_t output_param2; /* (Big-endian) */ + /* dword 5-7 */ + uint8_t reserved[12]; +} __packed __aligned(4); + +_Static_assert(sizeof(struct ufshci_task_mgmt_response_upiu) == 32, + "bad size for ufshci_task_mgmt_response_upiu"); +_Static_assert(sizeof(struct ufshci_task_mgmt_response_upiu) <= + UFSHCI_UTP_XFER_RESP_SIZE, + "bad size for ufshci_task_mgmt_response_upiu"); +_Static_assert(sizeof(struct ufshci_task_mgmt_response_upiu) % + UFSHCI_UPIU_ALIGNMENT == + 0, + "UPIU requires 64-bit alignment"); + /* UFS Spec 4.1, section 10.7.8 "QUERY REQUEST UPIU" */ enum ufshci_query_function { UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01, @@ -554,6 +631,7 @@ union ufshci_reponse_upiu { struct ufshci_upiu_header header; struct ufshci_cmd_response_upiu cmd_response_upiu; struct ufshci_query_response_upiu query_response_upiu; + struct ufshci_task_mgmt_response_upiu task_mgmt_response_upiu; struct ufshci_nop_in_upiu nop_in_upiu; }; diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c index 55d8363d3287..37bd32665b2b 100644 --- a/sys/dev/ufshci/ufshci_ctrlr.c +++ b/sys/dev/ufshci/ufshci_ctrlr.c @@ -154,12 +154,12 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev) /* TODO: Initialize interrupt Aggregation Control Register (UTRIACR) */ /* Allocate and initialize UTP Task Management Request List. */ - error = ufshci_utm_req_queue_construct(ctrlr); + error = ufshci_utmr_req_queue_construct(ctrlr); if (error) return (error); /* Allocate and initialize UTP Transfer Request List or SQ/CQ. */ - error = ufshci_ut_req_queue_construct(ctrlr); + error = ufshci_utr_req_queue_construct(ctrlr); if (error) return (error); @@ -179,8 +179,8 @@ ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev) /* TODO: Flush In-flight IOs */ /* Release resources */ - ufshci_utm_req_queue_destroy(ctrlr); - ufshci_ut_req_queue_destroy(ctrlr); + ufshci_utmr_req_queue_destroy(ctrlr); + ufshci_utr_req_queue_destroy(ctrlr); if (ctrlr->tag) bus_teardown_intr(ctrlr->dev, ctrlr->res, ctrlr->tag); @@ -215,8 +215,8 @@ ufshci_ctrlr_reset(struct ufshci_controller *ctrlr) ufshci_mmio_write_4(ctrlr, ie, 0); /* Release resources */ - ufshci_utm_req_queue_destroy(ctrlr); - ufshci_ut_req_queue_destroy(ctrlr); + ufshci_utmr_req_queue_destroy(ctrlr); + ufshci_utr_req_queue_destroy(ctrlr); /* Reset Host Controller */ error = ufshci_ctrlr_enable_host_ctrlr(ctrlr); @@ -232,12 +232,12 @@ ufshci_ctrlr_reset(struct ufshci_controller *ctrlr) ufshci_mmio_write_4(ctrlr, ie, ie); /* Allocate and initialize UTP Task Management Request List. */ - error = ufshci_utm_req_queue_construct(ctrlr); + error = ufshci_utmr_req_queue_construct(ctrlr); if (error) return (error); /* Allocate and initialize UTP Transfer Request List or SQ/CQ. */ - error = ufshci_ut_req_queue_construct(ctrlr); + error = ufshci_utr_req_queue_construct(ctrlr); if (error) return (error); @@ -245,6 +245,15 @@ ufshci_ctrlr_reset(struct ufshci_controller *ctrlr) } int +ufshci_ctrlr_submit_task_mgmt_request(struct ufshci_controller *ctrlr, + struct ufshci_request *req) +{ + return ( + ufshci_req_queue_submit_request(&ctrlr->task_mgmt_req_queue, req, + /*is_admin*/ false)); +} + +int ufshci_ctrlr_submit_admin_request(struct ufshci_controller *ctrlr, struct ufshci_request *req) { @@ -360,8 +369,8 @@ ufshci_ctrlr_start_config_hook(void *arg) TSENTER(); - if (ufshci_utm_req_queue_enable(ctrlr) == 0 && - ufshci_ut_req_queue_enable(ctrlr) == 0) + if (ufshci_utmr_req_queue_enable(ctrlr) == 0 && + ufshci_utr_req_queue_enable(ctrlr) == 0) ufshci_ctrlr_start(ctrlr); else ufshci_ctrlr_fail(ctrlr, false); @@ -445,9 +454,9 @@ ufshci_ctrlr_poll(struct ufshci_controller *ctrlr) } /* UTP Task Management Request Completion Status */ if (is & UFSHCIM(UFSHCI_IS_REG_UTMRCS)) { - ufshci_printf(ctrlr, "TODO: Implement UTMR completion\n"); ufshci_mmio_write_4(ctrlr, is, UFSHCIM(UFSHCI_IS_REG_UTMRCS)); - /* TODO: Implement UTMR completion */ + ufshci_req_queue_process_completions( + &ctrlr->task_mgmt_req_queue); } /* UTP Transfer Request Completion Status */ if (is & UFSHCIM(UFSHCI_IS_REG_UTRCS)) { diff --git a/sys/dev/ufshci/ufshci_ctrlr_cmd.c b/sys/dev/ufshci/ufshci_ctrlr_cmd.c index ddf28c58fa88..71d163d998af 100644 --- a/sys/dev/ufshci/ufshci_ctrlr_cmd.c +++ b/sys/dev/ufshci/ufshci_ctrlr_cmd.c @@ -8,6 +8,32 @@ #include "ufshci_private.h" void +ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr, + ufshci_cb_fn_t cb_fn, void *cb_arg, uint8_t function, uint8_t lun, + uint8_t task_tag, uint8_t iid) +{ + struct ufshci_request *req; + struct ufshci_task_mgmt_request_upiu *upiu; + + req = ufshci_allocate_request_vaddr(NULL, 0, M_WAITOK, cb_fn, cb_arg); + + req->request_size = sizeof(struct ufshci_task_mgmt_request_upiu); + req->response_size = sizeof(struct ufshci_task_mgmt_response_upiu); + + upiu = (struct ufshci_task_mgmt_request_upiu *)&req->request_upiu; + memset(upiu, 0, req->request_size); + upiu->header.trans_type = + UFSHCI_UPIU_TRANSACTION_CODE_TASK_MANAGEMENT_REQUEST; + upiu->header.lun = lun; + upiu->header.ext_iid_or_function = function; + upiu->input_param1 = lun; + upiu->input_param2 = task_tag; + upiu->input_param3 = iid; + + ufshci_ctrlr_submit_task_mgmt_request(ctrlr, req); +} + +void ufshci_ctrlr_cmd_send_nop(struct ufshci_controller *ctrlr, ufshci_cb_fn_t cb_fn, void *cb_arg) { diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h index ac58d44102a0..1a2742ae2e80 100644 --- a/sys/dev/ufshci/ufshci_private.h +++ b/sys/dev/ufshci/ufshci_private.h @@ -125,6 +125,8 @@ struct ufshci_qops { struct ufshci_tracker **tr); void (*ring_doorbell)(struct ufshci_controller *ctrlr, struct ufshci_tracker *tr); + bool (*is_doorbell_cleared)(struct ufshci_controller *ctrlr, + uint8_t slot); void (*clear_cpl_ntf)(struct ufshci_controller *ctrlr, struct ufshci_tracker *tr); bool (*process_cpl)(struct ufshci_req_queue *req_queue); @@ -143,7 +145,10 @@ struct ufshci_hw_queue { int domain; int cpu; - struct ufshci_utp_xfer_req_desc *utrd; + union { + struct ufshci_utp_xfer_req_desc *utrd; + struct ufshci_utp_task_mgmt_req_desc *utmrd; + }; bus_dma_tag_t dma_tag_queue; bus_dmamap_t queuemem_map; @@ -333,6 +338,8 @@ int ufshci_ctrlr_reset(struct ufshci_controller *ctrlr); void ufshci_ctrlr_start_config_hook(void *arg); void ufshci_ctrlr_poll(struct ufshci_controller *ctrlr); +int ufshci_ctrlr_submit_task_mgmt_request(struct ufshci_controller *ctrlr, + struct ufshci_request *req); int ufshci_ctrlr_submit_admin_request(struct ufshci_controller *ctrlr, struct ufshci_request *req); int ufshci_ctrlr_submit_io_request(struct ufshci_controller *ctrlr, @@ -351,6 +358,9 @@ int ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr); int ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr); /* Controller Command */ +void ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr, + ufshci_cb_fn_t cb_fn, void *cb_arg, uint8_t function, uint8_t lun, + uint8_t task_tag, uint8_t iid); void ufshci_ctrlr_cmd_send_nop(struct ufshci_controller *ctrlr, ufshci_cb_fn_t cb_fn, void *cb_arg); void ufshci_ctrlr_cmd_send_query_request(struct ufshci_controller *ctrlr, @@ -361,12 +371,12 @@ void ufshci_ctrlr_cmd_send_scsi_command(struct ufshci_controller *ctrlr, /* Request Queue */ bool ufshci_req_queue_process_completions(struct ufshci_req_queue *req_queue); -int ufshci_utm_req_queue_construct(struct ufshci_controller *ctrlr); -int ufshci_ut_req_queue_construct(struct ufshci_controller *ctrlr); -void ufshci_utm_req_queue_destroy(struct ufshci_controller *ctrlr); -void ufshci_ut_req_queue_destroy(struct ufshci_controller *ctrlr); -int ufshci_utm_req_queue_enable(struct ufshci_controller *ctrlr); -int ufshci_ut_req_queue_enable(struct ufshci_controller *ctrlr); +int ufshci_utmr_req_queue_construct(struct ufshci_controller *ctrlr); +int ufshci_utr_req_queue_construct(struct ufshci_controller *ctrlr); +void ufshci_utmr_req_queue_destroy(struct ufshci_controller *ctrlr); +void ufshci_utr_req_queue_destroy(struct ufshci_controller *ctrlr); +int ufshci_utmr_req_queue_enable(struct ufshci_controller *ctrlr); +int ufshci_utr_req_queue_enable(struct ufshci_controller *ctrlr); void ufshci_req_queue_fail(struct ufshci_controller *ctrlr, struct ufshci_hw_queue *hwq); int ufshci_req_queue_submit_request(struct ufshci_req_queue *req_queue, @@ -385,9 +395,17 @@ int ufshci_req_sdb_enable(struct ufshci_controller *ctrlr, struct ufshci_req_queue *req_queue); int ufshci_req_sdb_reserve_slot(struct ufshci_req_queue *req_queue, struct ufshci_tracker **tr); -void ufshci_req_sdb_ring_doorbell(struct ufshci_controller *ctrlr, +void ufshci_req_sdb_utmr_ring_doorbell(struct ufshci_controller *ctrlr, + struct ufshci_tracker *tr); +void ufshci_req_sdb_utr_ring_doorbell(struct ufshci_controller *ctrlr, + struct ufshci_tracker *tr); +bool ufshci_req_sdb_utmr_is_doorbell_cleared(struct ufshci_controller *ctrlr, + uint8_t slot); +bool ufshci_req_sdb_utr_is_doorbell_cleared(struct ufshci_controller *ctrlr, + uint8_t slot); +void ufshci_req_sdb_utmr_clear_cpl_ntf(struct ufshci_controller *ctrlr, struct ufshci_tracker *tr); -void ufshci_req_sdb_clear_cpl_ntf(struct ufshci_controller *ctrlr, +void ufshci_req_sdb_utr_clear_cpl_ntf(struct ufshci_controller *ctrlr, struct ufshci_tracker *tr); bool ufshci_req_sdb_process_cpl(struct ufshci_req_queue *req_queue); int ufshci_req_sdb_get_inflight_io(struct ufshci_controller *ctrlr); diff --git a/sys/dev/ufshci/ufshci_req_queue.c b/sys/dev/ufshci/ufshci_req_queue.c index cc9a2ddae768..bb6efa6d2ccc 100644 --- a/sys/dev/ufshci/ufshci_req_queue.c +++ b/sys/dev/ufshci/ufshci_req_queue.c @@ -19,21 +19,36 @@ static void ufshci_req_queue_submit_tracker(struct ufshci_req_queue *req_queue, struct ufshci_tracker *tr, enum ufshci_data_direction data_direction); -static const struct ufshci_qops sdb_qops = { +static const struct ufshci_qops sdb_utmr_qops = { .construct = ufshci_req_sdb_construct, .destroy = ufshci_req_sdb_destroy, .get_hw_queue = ufshci_req_sdb_get_hw_queue, .enable = ufshci_req_sdb_enable, .reserve_slot = ufshci_req_sdb_reserve_slot, .reserve_admin_slot = ufshci_req_sdb_reserve_slot, - .ring_doorbell = ufshci_req_sdb_ring_doorbell, - .clear_cpl_ntf = ufshci_req_sdb_clear_cpl_ntf, + .ring_doorbell = ufshci_req_sdb_utmr_ring_doorbell, + .is_doorbell_cleared = ufshci_req_sdb_utmr_is_doorbell_cleared, + .clear_cpl_ntf = ufshci_req_sdb_utmr_clear_cpl_ntf, + .process_cpl = ufshci_req_sdb_process_cpl, + .get_inflight_io = ufshci_req_sdb_get_inflight_io, +}; + +static const struct ufshci_qops sdb_utr_qops = { + .construct = ufshci_req_sdb_construct, + .destroy = ufshci_req_sdb_destroy, + .get_hw_queue = ufshci_req_sdb_get_hw_queue, + .enable = ufshci_req_sdb_enable, + .reserve_slot = ufshci_req_sdb_reserve_slot, + .reserve_admin_slot = ufshci_req_sdb_reserve_slot, + .ring_doorbell = ufshci_req_sdb_utr_ring_doorbell, + .is_doorbell_cleared = ufshci_req_sdb_utr_is_doorbell_cleared, + .clear_cpl_ntf = ufshci_req_sdb_utr_clear_cpl_ntf, .process_cpl = ufshci_req_sdb_process_cpl, .get_inflight_io = ufshci_req_sdb_get_inflight_io, }; int -ufshci_utm_req_queue_construct(struct ufshci_controller *ctrlr) +ufshci_utmr_req_queue_construct(struct ufshci_controller *ctrlr) { struct ufshci_req_queue *req_queue; int error; @@ -44,7 +59,7 @@ ufshci_utm_req_queue_construct(struct ufshci_controller *ctrlr) */ req_queue = &ctrlr->task_mgmt_req_queue; req_queue->queue_mode = UFSHCI_Q_MODE_SDB; - req_queue->qops = sdb_qops; + req_queue->qops = sdb_utmr_qops; error = req_queue->qops.construct(ctrlr, req_queue, UFSHCI_UTRM_ENTRIES, /*is_task_mgmt*/ true); @@ -53,21 +68,21 @@ ufshci_utm_req_queue_construct(struct ufshci_controller *ctrlr) } void -ufshci_utm_req_queue_destroy(struct ufshci_controller *ctrlr) +ufshci_utmr_req_queue_destroy(struct ufshci_controller *ctrlr) { ctrlr->task_mgmt_req_queue.qops.destroy(ctrlr, &ctrlr->task_mgmt_req_queue); } int -ufshci_utm_req_queue_enable(struct ufshci_controller *ctrlr) +ufshci_utmr_req_queue_enable(struct ufshci_controller *ctrlr) { return (ctrlr->task_mgmt_req_queue.qops.enable(ctrlr, &ctrlr->task_mgmt_req_queue)); } int -ufshci_ut_req_queue_construct(struct ufshci_controller *ctrlr) +ufshci_utr_req_queue_construct(struct ufshci_controller *ctrlr) { struct ufshci_req_queue *req_queue; int error; @@ -79,7 +94,7 @@ ufshci_ut_req_queue_construct(struct ufshci_controller *ctrlr) */ req_queue = &ctrlr->transfer_req_queue; req_queue->queue_mode = UFSHCI_Q_MODE_SDB; - req_queue->qops = sdb_qops; + req_queue->qops = sdb_utr_qops; error = req_queue->qops.construct(ctrlr, req_queue, UFSHCI_UTR_ENTRIES, /*is_task_mgmt*/ false); @@ -88,14 +103,14 @@ ufshci_ut_req_queue_construct(struct ufshci_controller *ctrlr) } void -ufshci_ut_req_queue_destroy(struct ufshci_controller *ctrlr) +ufshci_utr_req_queue_destroy(struct ufshci_controller *ctrlr) { ctrlr->transfer_req_queue.qops.destroy(ctrlr, &ctrlr->transfer_req_queue); } int -ufshci_ut_req_queue_enable(struct ufshci_controller *ctrlr) +ufshci_utr_req_queue_enable(struct ufshci_controller *ctrlr) { return (ctrlr->transfer_req_queue.qops.enable(ctrlr, &ctrlr->transfer_req_queue)); @@ -213,20 +228,30 @@ ufshci_req_queue_complete_tracker(struct ufshci_tracker *tr) struct ufshci_req_queue *req_queue = tr->req_queue; struct ufshci_request *req = tr->req; struct ufshci_completion cpl; - struct ufshci_utp_xfer_req_desc *desc; uint8_t ocs; bool retry, error, retriable; mtx_assert(&tr->hwq->qlock, MA_NOTOWNED); - bus_dmamap_sync(req_queue->dma_tag_ucd, req_queue->ucdmem_map, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + /* Copy the response from the Request Descriptor or UTP Command + * Descriptor. */ + if (req_queue->is_task_mgmt) { + cpl.size = tr->response_size; + memcpy(&cpl.response_upiu, + (void *)tr->hwq->utmrd[tr->slot_num].response_upiu, + cpl.size); - cpl.size = tr->response_size; - memcpy(&cpl.response_upiu, (void *)tr->ucd->response_upiu, cpl.size); + ocs = tr->hwq->utmrd[tr->slot_num].overall_command_status; + } else { + bus_dmamap_sync(req_queue->dma_tag_ucd, req_queue->ucdmem_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - desc = &tr->hwq->utrd[tr->slot_num]; - ocs = desc->overall_command_status; + cpl.size = tr->response_size; + memcpy(&cpl.response_upiu, (void *)tr->ucd->response_upiu, + cpl.size); + + ocs = tr->hwq->utrd[tr->slot_num].overall_command_status; + } error = ufshci_req_queue_response_is_error(req_queue, ocs, &cpl.response_upiu); @@ -358,7 +383,19 @@ ufshci_req_queue_prepare_prdt(struct ufshci_tracker *tr) } static void -ufshci_req_queue_fill_descriptor(struct ufshci_utp_xfer_req_desc *desc, +ufshci_req_queue_fill_utmr_descriptor( + struct ufshci_utp_task_mgmt_req_desc *desc, struct ufshci_request *req) +{ + memset(desc, 0, sizeof(struct ufshci_utp_task_mgmt_req_desc)); + desc->interrupt = true; + /* Set the initial value to Invalid. */ + desc->overall_command_status = UFSHCI_UTMR_OCS_INVALID; + + memcpy(desc->request_upiu, &req->request_upiu, req->request_size); +} + +static void +ufshci_req_queue_fill_utr_descriptor(struct ufshci_utp_xfer_req_desc *desc, uint8_t data_direction, const uint64_t paddr, const uint16_t response_off, const uint16_t response_len, const uint16_t prdt_off, const uint16_t prdt_entry_cnt) @@ -378,7 +415,7 @@ ufshci_req_queue_fill_descriptor(struct ufshci_utp_xfer_req_desc *desc, desc->data_direction = data_direction; desc->interrupt = true; /* Set the initial value to Invalid. */ - desc->overall_command_status = UFSHCI_OCS_INVALID; + desc->overall_command_status = UFSHCI_UTR_OCS_INVALID; desc->utp_command_descriptor_base_address = (uint32_t)(paddr & 0xffffffff); desc->utp_command_descriptor_base_address_upper = (uint32_t)(paddr >> @@ -407,26 +444,32 @@ ufshci_req_queue_submit_tracker(struct ufshci_req_queue *req_queue, /* TODO: Check timeout */ - request_len = req->request_size; - response_off = UFSHCI_UTP_XFER_REQ_SIZE; - response_len = req->response_size; - - /* Prepare UTP Command Descriptor */ - memcpy(tr->ucd, &req->request_upiu, request_len); - memset((uint8_t *)tr->ucd + response_off, 0, response_len); - - /* Prepare PRDT */ - if (req->payload_valid) - ufshci_req_queue_prepare_prdt(tr); - - bus_dmamap_sync(req_queue->dma_tag_ucd, req_queue->ucdmem_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - - /* Prepare UTP Transfer Request Descriptor. */ - ucd_paddr = tr->ucd_bus_addr; - ufshci_req_queue_fill_descriptor(&tr->hwq->utrd[slot_num], - data_direction, ucd_paddr, response_off, response_len, tr->prdt_off, - tr->prdt_entry_cnt); + if (req_queue->is_task_mgmt) { + /* Prepare UTP Task Management Request Descriptor. */ + ufshci_req_queue_fill_utmr_descriptor(&tr->hwq->utmrd[slot_num], + req); + } else { + request_len = req->request_size; + response_off = UFSHCI_UTP_XFER_REQ_SIZE; + response_len = req->response_size; + + /* Prepare UTP Command Descriptor */ + memcpy(tr->ucd, &req->request_upiu, request_len); + memset((uint8_t *)tr->ucd + response_off, 0, response_len); + + /* Prepare PRDT */ + if (req->payload_valid) + ufshci_req_queue_prepare_prdt(tr); + + /* Prepare UTP Transfer Request Descriptor. */ + ucd_paddr = tr->ucd_bus_addr; + ufshci_req_queue_fill_utr_descriptor(&tr->hwq->utrd[slot_num], + data_direction, ucd_paddr, response_off, response_len, + tr->prdt_off, tr->prdt_entry_cnt); + + bus_dmamap_sync(req_queue->dma_tag_ucd, req_queue->ucdmem_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + } bus_dmamap_sync(tr->hwq->dma_tag_queue, tr->hwq->queuemem_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); diff --git a/sys/dev/ufshci/ufshci_req_sdb.c b/sys/dev/ufshci/ufshci_req_sdb.c index b1f303afaef5..834a459d48e3 100644 --- a/sys/dev/ufshci/ufshci_req_sdb.c +++ b/sys/dev/ufshci/ufshci_req_sdb.c @@ -26,12 +26,6 @@ ufshci_req_sdb_cmd_desc_destroy(struct ufshci_req_queue *req_queue) tr = hwq->act_tr[i]; bus_dmamap_destroy(req_queue->dma_tag_payload, tr->payload_dma_map); - free(tr, M_UFSHCI); - } - - if (hwq->act_tr) { - free(hwq->act_tr, M_UFSHCI); - hwq->act_tr = NULL; } if (req_queue->ucd) { @@ -76,7 +70,6 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue, uint32_t num_entries, struct ufshci_controller *ctrlr) { struct ufshci_hw_queue *hwq = &req_queue->hwq[UFSHCI_SDB_Q]; - struct ufshci_tracker *tr; size_t ucd_allocsz, payload_allocsz; uint8_t *ucdmem; int i, error; @@ -134,27 +127,14 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue, goto out; } - hwq->act_tr = malloc_domainset(sizeof(struct ufshci_tracker *) * - req_queue->num_entries, - M_UFSHCI, DOMAINSET_PREF(req_queue->domain), M_ZERO | M_WAITOK); - for (i = 0; i < req_queue->num_trackers; i++) { - tr = malloc_domainset(sizeof(struct ufshci_tracker), M_UFSHCI, - DOMAINSET_PREF(req_queue->domain), M_ZERO | M_WAITOK); - bus_dmamap_create(req_queue->dma_tag_payload, 0, - &tr->payload_dma_map); + &hwq->act_tr[i]->payload_dma_map); - tr->req_queue = req_queue; - tr->slot_num = i; - tr->slot_state = UFSHCI_SLOT_STATE_FREE; - - tr->ucd = (struct ufshci_utp_cmd_desc *)ucdmem; - tr->ucd_bus_addr = hwq->ucd_bus_addr[i]; + hwq->act_tr[i]->ucd = (struct ufshci_utp_cmd_desc *)ucdmem; + hwq->act_tr[i]->ucd_bus_addr = hwq->ucd_bus_addr[i]; ucdmem += sizeof(struct ufshci_utp_cmd_desc); - - hwq->act_tr[i] = tr; } return (0); @@ -163,25 +143,16 @@ out: return (ENOMEM); } -static bool -ufshci_req_sdb_is_doorbell_cleared(struct ufshci_controller *ctrlr, - uint8_t slot) -{ - uint32_t utrldbr; - - utrldbr = ufshci_mmio_read_4(ctrlr, utrldbr); - return (!(utrldbr & (1 << slot))); -} - int ufshci_req_sdb_construct(struct ufshci_controller *ctrlr, struct ufshci_req_queue *req_queue, uint32_t num_entries, bool is_task_mgmt) { struct ufshci_hw_queue *hwq; - size_t allocsz; + size_t desc_size, alloc_size; uint64_t queuemem_phys; uint8_t *queuemem; - int error; + struct ufshci_tracker *tr; + int i, error; req_queue->ctrlr = ctrlr; req_queue->is_task_mgmt = is_task_mgmt; @@ -209,10 +180,13 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr, * Descriptor (UTRD) or UTP Task Management Request Descriptor (UTMRD)) * Note: UTRD/UTMRD format is restricted to 1024-byte alignment. */ - allocsz = num_entries * sizeof(struct ufshci_utp_xfer_req_desc); + desc_size = is_task_mgmt ? + sizeof(struct ufshci_utp_task_mgmt_req_desc) : + sizeof(struct ufshci_utp_xfer_req_desc); + alloc_size = num_entries * desc_size; error = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev), 1024, ctrlr->page_size, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, - allocsz, 1, allocsz, 0, NULL, NULL, &hwq->dma_tag_queue); + alloc_size, 1, alloc_size, 0, NULL, NULL, &hwq->dma_tag_queue); if (error != 0) { ufshci_printf(ctrlr, "request queue tag create failed %d\n", error); @@ -227,7 +201,7 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr, } if (bus_dmamap_load(hwq->dma_tag_queue, hwq->queuemem_map, queuemem, - allocsz, ufshci_single_map, &queuemem_phys, 0) != 0) { + alloc_size, ufshci_single_map, &queuemem_phys, 0) != 0) { ufshci_printf(ctrlr, "failed to load request queue memory\n"); bus_dmamem_free(hwq->dma_tag_queue, hwq->utrd, hwq->queuemem_map); @@ -238,13 +212,30 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr, hwq->num_intr_handler_calls = 0; hwq->num_retries = 0; hwq->num_failures = 0; - hwq->utrd = (struct ufshci_utp_xfer_req_desc *)queuemem; hwq->req_queue_addr = queuemem_phys; + /* Allocate trackers */ + hwq->act_tr = malloc_domainset(sizeof(struct ufshci_tracker *) * + req_queue->num_entries, + M_UFSHCI, DOMAINSET_PREF(req_queue->domain), M_ZERO | M_WAITOK); + + for (i = 0; i < req_queue->num_trackers; i++) { + tr = malloc_domainset(sizeof(struct ufshci_tracker), M_UFSHCI, + DOMAINSET_PREF(req_queue->domain), M_ZERO | M_WAITOK); + + tr->req_queue = req_queue; + tr->slot_num = i; + tr->slot_state = UFSHCI_SLOT_STATE_FREE; + + hwq->act_tr[i] = tr; + } + if (is_task_mgmt) { /* UTP Task Management Request (UTMR) */ uint32_t utmrlba, utmrlbau; + hwq->utmrd = (struct ufshci_utp_task_mgmt_req_desc *)queuemem; + utmrlba = hwq->req_queue_addr & 0xffffffff; utmrlbau = hwq->req_queue_addr >> 32; ufshci_mmio_write_4(ctrlr, utmrlba, utmrlba); @@ -253,6 +244,8 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr, /* UTP Transfer Request (UTR) */ uint32_t utrlba, utrlbau; + hwq->utrd = (struct ufshci_utp_xfer_req_desc *)queuemem; + /* * Allocate physical memory for the command descriptor. * UTP Transfer Request (UTR) requires memory for a separate @@ -284,10 +277,22 @@ ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr, struct ufshci_req_queue *req_queue) { struct ufshci_hw_queue *hwq = &req_queue->hwq[UFSHCI_SDB_Q]; + struct ufshci_tracker *tr; + int i; if (!req_queue->is_task_mgmt) ufshci_req_sdb_cmd_desc_destroy(&ctrlr->transfer_req_queue); + for (i = 0; i < req_queue->num_trackers; i++) { + tr = hwq->act_tr[i]; + free(tr, M_UFSHCI); + } + + if (hwq->act_tr) { + free(hwq->act_tr, M_UFSHCI); + hwq->act_tr = NULL; + } + if (hwq->utrd != NULL) { bus_dmamap_unload(hwq->dma_tag_queue, hwq->queuemem_map); bus_dmamem_free(hwq->dma_tag_queue, hwq->utrd, @@ -389,7 +394,18 @@ ufshci_req_sdb_reserve_slot(struct ufshci_req_queue *req_queue, } void -ufshci_req_sdb_clear_cpl_ntf(struct ufshci_controller *ctrlr, +ufshci_req_sdb_utmr_clear_cpl_ntf(struct ufshci_controller *ctrlr, + struct ufshci_tracker *tr) +{ + /* + * NOP + * UTP Task Management does not have a Completion Notification + * Register. + */ +} + +void +ufshci_req_sdb_utr_clear_cpl_ntf(struct ufshci_controller *ctrlr, struct ufshci_tracker *tr) { uint32_t utrlcnr; @@ -399,7 +415,19 @@ ufshci_req_sdb_clear_cpl_ntf(struct ufshci_controller *ctrlr, } void -ufshci_req_sdb_ring_doorbell(struct ufshci_controller *ctrlr, +ufshci_req_sdb_utmr_ring_doorbell(struct ufshci_controller *ctrlr, + struct ufshci_tracker *tr) +{ + uint32_t utmrldbr = 0; + + utmrldbr |= 1 << tr->slot_num; + ufshci_mmio_write_4(ctrlr, utmrldbr, utmrldbr); + + tr->req_queue->hwq[UFSHCI_SDB_Q].num_cmds++; +} + +void +ufshci_req_sdb_utr_ring_doorbell(struct ufshci_controller *ctrlr, struct ufshci_tracker *tr) { uint32_t utrldbr = 0; @@ -408,9 +436,26 @@ ufshci_req_sdb_ring_doorbell(struct ufshci_controller *ctrlr, ufshci_mmio_write_4(ctrlr, utrldbr, utrldbr); tr->req_queue->hwq[UFSHCI_SDB_Q].num_cmds++; +} + +bool +ufshci_req_sdb_utmr_is_doorbell_cleared(struct ufshci_controller *ctrlr, + uint8_t slot) +{ + uint32_t utmrldbr; + + utmrldbr = ufshci_mmio_read_4(ctrlr, utmrldbr); + return (!(utmrldbr & (1 << slot))); +} - // utrldbr = ufshci_mmio_read_4(ctrlr, utrldbr); - // printf("DB=0x%08x\n", utrldbr); +bool +ufshci_req_sdb_utr_is_doorbell_cleared(struct ufshci_controller *ctrlr, + uint8_t slot) +{ + uint32_t utrldbr; + + utrldbr = ufshci_mmio_read_4(ctrlr, utrldbr); + return (!(utrldbr & (1 << slot))); } bool @@ -435,7 +480,7 @@ ufshci_req_sdb_process_cpl(struct ufshci_req_queue *req_queue) * is cleared. */ if (tr->slot_state == UFSHCI_SLOT_STATE_SCHEDULED && - ufshci_req_sdb_is_doorbell_cleared(req_queue->ctrlr, + req_queue->qops.is_doorbell_cleared(req_queue->ctrlr, slot)) { ufshci_req_queue_complete_tracker(tr); done = true; diff --git a/sys/dev/usb/input/uhid.c b/sys/dev/usb/input/uhid.c index a31081663f0c..e2b97f5accac 100644 --- a/sys/dev/usb/input/uhid.c +++ b/sys/dev/usb/input/uhid.c @@ -40,8 +40,6 @@ * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf */ -#include "opt_hid.h" - #include <sys/stdint.h> #include <sys/stddef.h> #include <sys/param.h> @@ -928,11 +926,7 @@ static device_method_t uhid_methods[] = { }; static driver_t uhid_driver = { -#ifdef HIDRAW_MAKE_UHID_ALIAS - .name = "hidraw", -#else .name = "uhid", -#endif .methods = uhid_methods, .size = sizeof(struct uhid_softc), }; diff --git a/sys/dev/usb/input/usbhid.c b/sys/dev/usb/input/usbhid.c index df810012b3f8..cba3f34053e5 100644 --- a/sys/dev/usb/input/usbhid.c +++ b/sys/dev/usb/input/usbhid.c @@ -114,6 +114,7 @@ struct usbhid_xfer_ctx { void *cb_ctx; int waiters; bool influx; + bool no_readahead; }; struct usbhid_softc { @@ -272,7 +273,7 @@ usbhid_intr_handler_cb(struct usbhid_xfer_ctx *xfer_ctx) sc->sc_intr_handler(sc->sc_intr_ctx, xfer_ctx->buf, xfer_ctx->req.intr.actlen); - return (0); + return (xfer_ctx->no_readahead ? ECANCELED : 0); } static int @@ -430,6 +431,7 @@ usbhid_intr_start(device_t dev, device_t child __unused) .cb = usbhid_intr_handler_cb, .cb_ctx = sc, .buf = sc->sc_intr_buf, + .no_readahead = hid_test_quirk(&sc->sc_hw, HQ_NO_READAHEAD), }; sc->sc_xfer_ctx[POLL_XFER(USBHID_INTR_IN_DT)] = (struct usbhid_xfer_ctx) { .req.intr.maxlen = @@ -705,6 +707,10 @@ usbhid_ioctl(device_t dev, device_t child __unused, unsigned long cmd, if (error == 0) ucr->ucr_actlen = UGETW(req.ctrl.wLength); break; + case USB_GET_DEVICEINFO: + error = usbd_fill_deviceinfo(sc->sc_udev, + (struct usb_device_info *)data); + break; default: error = EINVAL; } diff --git a/sys/dev/usb/net/if_ipheth.c b/sys/dev/usb/net/if_ipheth.c index f70113c53eb4..cfa800707391 100644 --- a/sys/dev/usb/net/if_ipheth.c +++ b/sys/dev/usb/net/if_ipheth.c @@ -55,6 +55,7 @@ #include <net/if_var.h> #include <dev/usb/usb.h> +#include <dev/usb/usb_cdc.h> #include <dev/usb/usbdi.h> #include <dev/usb/usbdi_util.h> #include "usbdevs.h" @@ -81,6 +82,9 @@ static uether_fn_t ipheth_start; static uether_fn_t ipheth_setmulti; static uether_fn_t ipheth_setpromisc; +static ipheth_consumer_t ipheth_consume_read; +static ipheth_consumer_t ipheth_consume_read_ncm; + #ifdef USB_DEBUG static int ipheth_debug = 0; @@ -96,7 +100,31 @@ static const struct usb_config ipheth_config[IPHETH_N_TRANSFER] = { .direction = UE_DIR_RX, .frames = IPHETH_RX_FRAMES_MAX, .bufsize = (IPHETH_RX_FRAMES_MAX * MCLBYTES), - .flags = {.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, + .flags = {.short_frames_ok = 1, .short_xfer_ok = 1, .ext_buffer = 1,}, + .callback = ipheth_bulk_read_callback, + .timeout = 0, /* no timeout */ + }, + + [IPHETH_BULK_TX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_TX, + .frames = IPHETH_TX_FRAMES_MAX, + .bufsize = (IPHETH_TX_FRAMES_MAX * IPHETH_BUF_SIZE), + .flags = {.force_short_xfer = 1,}, + .callback = ipheth_bulk_write_callback, + .timeout = IPHETH_TX_TIMEOUT, + }, +}; + +static const struct usb_config ipheth_config_ncm[IPHETH_N_TRANSFER] = { + [IPHETH_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_RX, + .frames = 1, + .bufsize = IPHETH_RX_NCM_BUF_SIZE, + .flags = {.short_frames_ok = 1, .short_xfer_ok = 1,}, .callback = ipheth_bulk_read_callback, .timeout = 0, /* no timeout */ }, @@ -204,6 +232,21 @@ ipheth_get_mac_addr(struct ipheth_softc *sc) return (0); } +static bool +ipheth_enable_ncm(struct ipheth_softc *sc) +{ + struct usb_device_request req; + + req.bmRequestType = UT_WRITE_VENDOR_INTERFACE; + req.bRequest = IPHETH_CMD_ENABLE_NCM; + USETW(req.wValue, 0); + req.wIndex[0] = sc->sc_iface_no; + req.wIndex[1] = 0; + USETW(req.wLength, 0); + + return (usbd_do_request(sc->sc_ue.ue_udev, NULL, &req, NULL) == 0); +} + static int ipheth_probe(device_t dev) { @@ -221,6 +264,7 @@ ipheth_attach(device_t dev) struct ipheth_softc *sc = device_get_softc(dev); struct usb_ether *ue = &sc->sc_ue; struct usb_attach_arg *uaa = device_get_ivars(dev); + const struct usb_config *config; int error; sc->sc_iface_no = uaa->info.bIfaceIndex; @@ -235,18 +279,29 @@ ipheth_attach(device_t dev) device_printf(dev, "Cannot set alternate setting\n"); goto detach; } - error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no, - sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx); - if (error) { - device_printf(dev, "Cannot setup USB transfers\n"); - goto detach; - } + ue->ue_sc = sc; ue->ue_dev = dev; ue->ue_udev = uaa->device; ue->ue_mtx = &sc->sc_mtx; ue->ue_methods = &ipheth_ue_methods; + if (ipheth_enable_ncm(sc)) { + config = ipheth_config_ncm; + sc->is_ncm = true; + sc->consume = &ipheth_consume_read_ncm; + } else { + config = ipheth_config; + sc->consume = &ipheth_consume_read; + } + + error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no, sc->sc_xfer, + config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx); + if (error) { + device_printf(dev, "Cannot setup USB transfers\n"); + goto detach; + } + error = ipheth_get_mac_addr(sc); if (error) { device_printf(dev, "Cannot get MAC address\n"); @@ -389,12 +444,9 @@ ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) int actlen; int aframes; - usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); - - DPRINTFN(1, "\n"); - switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: + usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", actlen, aframes); @@ -471,53 +523,40 @@ ipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) uint8_t x; int actlen; int aframes; - int len; - - usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: - + usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); DPRINTF("received %u bytes in %u frames\n", actlen, aframes); - for (x = 0; x != aframes; x++) { - m = sc->sc_rx_buf[x]; - sc->sc_rx_buf[x] = NULL; - len = usbd_xfer_frame_len(xfer, x); - - if (len < (int)(sizeof(struct ether_header) + - IPHETH_RX_ADJ)) { - m_freem(m); - continue; - } - - m_adj(m, IPHETH_RX_ADJ); - - /* queue up mbuf */ - uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ); - } + for (x = 0; x != aframes; x++) + sc->consume(xfer, x); /* FALLTHROUGH */ case USB_ST_SETUP: - - for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) { - if (sc->sc_rx_buf[x] == NULL) { - m = uether_newbuf(); - if (m == NULL) - goto tr_stall; - - /* cancel alignment for ethernet */ - m_adj(m, ETHER_ALIGN); - - sc->sc_rx_buf[x] = m; - } else { - m = sc->sc_rx_buf[x]; + if (!sc->is_ncm) { + for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) { + if (sc->sc_rx_buf[x] == NULL) { + m = uether_newbuf(); + if (m == NULL) + goto tr_stall; + + /* cancel alignment for ethernet */ + m_adj(m, ETHER_ALIGN); + + sc->sc_rx_buf[x] = m; + } else { + m = sc->sc_rx_buf[x]; + } + usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); } - - usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); + usbd_xfer_set_frames(xfer, x); + } else { + usbd_xfer_set_frame_len(xfer, 0, + IPHETH_RX_NCM_BUF_SIZE); + usbd_xfer_set_frames(xfer, 1); } - /* set number of frames and start hardware */ - usbd_xfer_set_frames(xfer, x); + usbd_transfer_submit(xfer); /* flush any received frames */ uether_rxflush(&sc->sc_ue); @@ -539,3 +578,86 @@ ipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) break; } } + +static void +ipheth_consume_read(struct usb_xfer *xfer, int x) +{ + struct ipheth_softc *sc = usbd_xfer_softc(xfer); + struct mbuf *m = sc->sc_rx_buf[x]; + int len; + + sc->sc_rx_buf[x] = NULL; + len = usbd_xfer_frame_len(xfer, x); + + if (len < (int)(sizeof(struct ether_header) + IPHETH_RX_ADJ)) { + m_freem(m); + return; + } + + m_adj(m, IPHETH_RX_ADJ); + + /* queue up mbuf */ + uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ); +} + +static void +ipheth_consume_read_ncm(struct usb_xfer *xfer, int x) +{ + struct ipheth_softc *sc = usbd_xfer_softc(xfer); + struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0); + struct ncm_data_cache ncm; + if_t ifp = uether_getifp(&sc->sc_ue); + struct mbuf *new_buf; + int i, actlen; + uint16_t dp_offset, dp_len; + + usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); + + if (actlen < IPHETH_NCM_HEADER_SIZE) + return; + + usbd_copy_out(pc, 0, &ncm.hdr, sizeof(ncm.hdr)); + + if (UGETDW(ncm.hdr.dwSignature) != 0x484D434E) + return; + + /* Dpt follows the hdr on iOS */ + if (UGETW(ncm.hdr.wDptIndex) != (int)(sizeof(struct usb_ncm16_hdr))) + return; + + usbd_copy_out(pc, UGETW(ncm.hdr.wDptIndex), &ncm.dpt, sizeof(ncm.dpt)); + + if (UGETDW(ncm.dpt.dwSignature) != 0x304D434E) + return; + + usbd_copy_out(pc, UGETW(ncm.hdr.wDptIndex) + sizeof(ncm.dpt), &ncm.dp, + sizeof(ncm.dp)); + + for (i = 0; i < IPHETH_NCM_DPT_DP_NUM; ++i) { + dp_offset = UGETW(ncm.dp[i].wFrameIndex); + dp_len = UGETW(ncm.dp[i].wFrameLength); + + /* (3.3.1 USB CDC NCM spec v1.0) */ + if (dp_offset == 0 && dp_len == 0) + break; + + if (dp_offset < IPHETH_NCM_HEADER_SIZE || dp_offset >= actlen || + actlen < (dp_len + dp_offset) || + dp_len < sizeof(struct ether_header)) { + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + continue; + } + if (dp_len > (MCLBYTES - ETHER_ALIGN)) { + if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); + continue; + } + + new_buf = uether_newbuf(); + if (new_buf == NULL) { + if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); + continue; + } + usbd_copy_out(pc, dp_offset, new_buf->m_data, dp_len); + uether_rxmbuf(&sc->sc_ue, new_buf, dp_len); + } +} diff --git a/sys/dev/usb/net/if_iphethvar.h b/sys/dev/usb/net/if_iphethvar.h index 203bb96b6f22..d637e8f67d01 100644 --- a/sys/dev/usb/net/if_iphethvar.h +++ b/sys/dev/usb/net/if_iphethvar.h @@ -41,6 +41,7 @@ #define IPHETH_BUF_SIZE 1514 #define IPHETH_TX_TIMEOUT 5000 /* ms */ +#define IPHETH_RX_NCM_BUF_SIZE 65536 #define IPHETH_RX_FRAMES_MAX 1 #define IPHETH_TX_FRAMES_MAX 8 @@ -55,10 +56,20 @@ #define IPHETH_CTRL_TIMEOUT 5000 /* ms */ #define IPHETH_CMD_GET_MACADDR 0x00 +#define IPHETH_CMD_ENABLE_NCM 0x04 #define IPHETH_CMD_CARRIER_CHECK 0x45 #define IPHETH_CARRIER_ON 0x04 +#define IPHETH_NCM_DPT_DP_NUM 22 +#define IPHETH_NCM_DPT_HEADER_SIZE \ + (sizeof(struct usb_ncm16_dpt) + \ + IPHETH_NCM_DPT_DP_NUM * sizeof(struct usb_ncm16_dp)) +#define IPHETH_NCM_HEADER_SIZE \ + (sizeof(struct usb_ncm16_hdr) + IPHETH_NCM_DPT_HEADER_SIZE) + +typedef void (ipheth_consumer_t)(struct usb_xfer *xfer, int idx); + enum { IPHETH_BULK_TX, IPHETH_BULK_RX, @@ -76,6 +87,16 @@ struct ipheth_softc { uint8_t sc_data[IPHETH_CTRL_BUF_SIZE]; uint8_t sc_iface_no; uint8_t sc_carrier_on; + + bool is_ncm; + + ipheth_consumer_t *consume; +}; + +struct ncm_data_cache { + struct usb_ncm16_hdr hdr; + struct usb_ncm16_dpt dpt; + struct usb_ncm16_dp dp[IPHETH_NCM_DPT_DP_NUM]; }; #define IPHETH_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 60c2d6745b3f..f0989972f49f 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -3111,3 +3111,51 @@ usbd_get_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep) { return (ep->ep_mode); } + +/*------------------------------------------------------------------------* + * usbd_fill_deviceinfo + * + * This function dumps information about an USB device to the + * structure pointed to by the "di" argument. + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +int +usbd_fill_deviceinfo(struct usb_device *udev, struct usb_device_info *di) +{ + struct usb_device *hub; + + bzero(di, sizeof(di[0])); + + di->udi_bus = device_get_unit(udev->bus->bdev); + di->udi_addr = udev->address; + di->udi_index = udev->device_index; + strlcpy(di->udi_serial, usb_get_serial(udev), sizeof(di->udi_serial)); + strlcpy(di->udi_vendor, usb_get_manufacturer(udev), sizeof(di->udi_vendor)); + strlcpy(di->udi_product, usb_get_product(udev), sizeof(di->udi_product)); + usb_printbcd(di->udi_release, sizeof(di->udi_release), + UGETW(udev->ddesc.bcdDevice)); + di->udi_vendorNo = UGETW(udev->ddesc.idVendor); + di->udi_productNo = UGETW(udev->ddesc.idProduct); + di->udi_releaseNo = UGETW(udev->ddesc.bcdDevice); + di->udi_class = udev->ddesc.bDeviceClass; + di->udi_subclass = udev->ddesc.bDeviceSubClass; + di->udi_protocol = udev->ddesc.bDeviceProtocol; + di->udi_config_no = udev->curr_config_no; + di->udi_config_index = udev->curr_config_index; + di->udi_power = udev->flags.self_powered ? 0 : udev->power; + di->udi_speed = udev->speed; + di->udi_mode = udev->flags.usb_mode; + di->udi_power_mode = udev->power_mode; + di->udi_suspended = udev->flags.peer_suspended; + + hub = udev->parent_hub; + if (hub) { + di->udi_hubaddr = hub->address; + di->udi_hubindex = hub->device_index; + di->udi_hubport = udev->port_no; + } + return (0); +} diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c index c0af27d77e5d..ccb0b2184ec4 100644 --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -831,42 +831,7 @@ ugen_get_iface_driver(struct usb_fifo *f, struct usb_gen_descriptor *ugd) int ugen_fill_deviceinfo(struct usb_fifo *f, struct usb_device_info *di) { - struct usb_device *udev; - struct usb_device *hub; - - udev = f->udev; - - bzero(di, sizeof(di[0])); - - di->udi_bus = device_get_unit(udev->bus->bdev); - di->udi_addr = udev->address; - di->udi_index = udev->device_index; - strlcpy(di->udi_serial, usb_get_serial(udev), sizeof(di->udi_serial)); - strlcpy(di->udi_vendor, usb_get_manufacturer(udev), sizeof(di->udi_vendor)); - strlcpy(di->udi_product, usb_get_product(udev), sizeof(di->udi_product)); - usb_printbcd(di->udi_release, sizeof(di->udi_release), - UGETW(udev->ddesc.bcdDevice)); - di->udi_vendorNo = UGETW(udev->ddesc.idVendor); - di->udi_productNo = UGETW(udev->ddesc.idProduct); - di->udi_releaseNo = UGETW(udev->ddesc.bcdDevice); - di->udi_class = udev->ddesc.bDeviceClass; - di->udi_subclass = udev->ddesc.bDeviceSubClass; - di->udi_protocol = udev->ddesc.bDeviceProtocol; - di->udi_config_no = udev->curr_config_no; - di->udi_config_index = udev->curr_config_index; - di->udi_power = udev->flags.self_powered ? 0 : udev->power; - di->udi_speed = udev->speed; - di->udi_mode = udev->flags.usb_mode; - di->udi_power_mode = udev->power_mode; - di->udi_suspended = udev->flags.peer_suspended; - - hub = udev->parent_hub; - if (hub) { - di->udi_hubaddr = hub->address; - di->udi_hubindex = hub->device_index; - di->udi_hubport = udev->port_no; - } - return (0); + return (usbd_fill_deviceinfo(f->udev, di)); } int diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index 08d130aa2868..0826d9f078c4 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -38,6 +38,7 @@ struct usb_process; struct usb_proc_msg; struct usb_mbuf; struct usb_fs_privdata; +struct usb_device_info; struct mbuf; typedef enum { /* keep in sync with usb_errstr_table */ @@ -587,6 +588,8 @@ usb_error_t usbd_set_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep, uint8_t ep_mode); uint8_t usbd_get_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep); +int usbd_fill_deviceinfo(struct usb_device *udev, + struct usb_device_info *di); const struct usb_device_id *usbd_lookup_id_by_info( const struct usb_device_id *id, usb_size_t sizeof_id, diff --git a/sys/dev/watchdog/watchdog.c b/sys/dev/watchdog/watchdog.c index e6b6dc1eac70..e1b2e08c3f10 100644 --- a/sys/dev/watchdog/watchdog.c +++ b/sys/dev/watchdog/watchdog.c @@ -50,11 +50,20 @@ #include <sys/syscallsubr.h> /* kern_clock_gettime() */ -static int wd_set_pretimeout(int newtimeout, int disableiftoolong); +#ifdef COMPAT_FREEBSD14 +#define WDIOCPATPAT_14 _IOW('W', 42, u_int) /* pat the watchdog */ +#define WDIOC_SETTIMEOUT_14 _IOW('W', 43, int) /* set/reset the timer */ +#define WDIOC_GETTIMEOUT_14 _IOR('W', 44, int) /* get total timeout */ +#define WDIOC_GETTIMELEFT_14 _IOR('W', 45, int) /* get time left */ +#define WDIOC_GETPRETIMEOUT_14 _IOR('W', 46, int) /* get the pre-timeout */ +#define WDIOC_SETPRETIMEOUT_14 _IOW('W', 47, int) /* set the pre-timeout */ +#endif + +static int wd_set_pretimeout(sbintime_t newtimeout, int disableiftoolong); static void wd_timeout_cb(void *arg); static struct callout wd_pretimeo_handle; -static int wd_pretimeout; +static sbintime_t wd_pretimeout; static int wd_pretimeout_act = WD_SOFT_LOG; static struct callout wd_softtimeo_handle; @@ -63,6 +72,8 @@ static int wd_softtimer; /* true = use softtimer instead of hardware static int wd_softtimeout_act = WD_SOFT_LOG; /* action for the software timeout */ static struct cdev *wd_dev; +static volatile sbintime_t wd_last_sbt; /* last timeout value (sbt) */ +static sbintime_t wd_last_sbt_sysctl; /* last timeout value (sbt) */ static volatile u_int wd_last_u; /* last timeout value set by kern_do_pat */ static u_int wd_last_u_sysctl; /* last timeout value set by kern_do_pat */ static u_int wd_last_u_sysctl_secs; /* wd_last_u in seconds */ @@ -73,6 +84,8 @@ SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u, CTLFLAG_RD, &wd_last_u_sysctl, 0, "Watchdog last update time"); SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u_secs, CTLFLAG_RD, &wd_last_u_sysctl_secs, 0, "Watchdog last update time"); +SYSCTL_SBINTIME_MSEC(_hw_watchdog, OID_AUTO, wd_last_msecs, CTLFLAG_RD, + &wd_last_sbt_sysctl, "Watchdog last update time (milliseconds)"); static int wd_lastpat_valid = 0; static time_t wd_lastpat = 0; /* when the watchdog was last patted */ @@ -80,105 +93,94 @@ static time_t wd_lastpat = 0; /* when the watchdog was last patted */ /* Hook for external software watchdog to register for use if needed */ void (*wdog_software_attach)(void); -static void -pow2ns_to_ts(int pow2ns, struct timespec *ts) +/* Legacy interface to watchdog. */ +int +wdog_kern_pat(u_int utim) { - uint64_t ns; + sbintime_t sbt; - ns = 1ULL << pow2ns; - ts->tv_sec = ns / 1000000000ULL; - ts->tv_nsec = ns % 1000000000ULL; -} + if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0) + return (EINVAL); -static int -pow2ns_to_ticks(int pow2ns) -{ - struct timeval tv; - struct timespec ts; + if ((utim & WD_LASTVAL) != 0) { + return (wdog_control(WD_CTRL_RESET)); + } - pow2ns_to_ts(pow2ns, &ts); - TIMESPEC_TO_TIMEVAL(&tv, &ts); - return (tvtohz(&tv)); + utim &= WD_INTERVAL; + if (utim == WD_TO_NEVER) + sbt = 0; + else + sbt = nstosbt(1 << utim); + + return (wdog_kern_pat_sbt(sbt)); } -static int -seconds_to_pow2ns(int seconds) +int +wdog_control(int ctrl) { - uint64_t power; - uint64_t ns; - uint64_t shifted; - - ns = ((uint64_t)seconds) * 1000000000ULL; - power = flsll(ns); - shifted = 1ULL << power; - if (shifted <= ns) { - power++; + /* Disable takes precedence */ + if (ctrl == WD_CTRL_DISABLE) { + wdog_kern_pat(0); } - return (power); + + if ((ctrl & WD_CTRL_RESET) != 0) { + wdog_kern_pat_sbt(wd_last_sbt); + } else if ((ctrl & WD_CTRL_ENABLE) != 0) { + wdog_kern_pat_sbt(wd_last_sbt); + } + + return (0); } int -wdog_kern_pat(u_int utim) +wdog_kern_pat_sbt(sbintime_t sbt) { - int error; - static int first = 1; - - if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0) - return (EINVAL); - - if ((utim & WD_LASTVAL) != 0) { - /* - * if WD_LASTVAL is set, fill in the bits for timeout - * from the saved value in wd_last_u. - */ - MPASS((wd_last_u & ~WD_INTERVAL) == 0); - utim &= ~WD_LASTVAL; - utim |= wd_last_u; - } else { - /* - * Otherwise save the new interval. - * This can be zero (to disable the watchdog) - */ - wd_last_u = (utim & WD_INTERVAL); + sbintime_t error_sbt = 0; + int pow2ns = 0; + int error = 0; + static bool first = true; + + /* legacy uses power-of-2-nanoseconds time. */ + if (sbt != 0) { + pow2ns = flsl(sbttons(sbt)); + } + if (wd_last_sbt != sbt) { + wd_last_u = pow2ns; wd_last_u_sysctl = wd_last_u; - wd_last_u_sysctl_secs = pow2ns_to_ticks(wd_last_u) / hz; + wd_last_u_sysctl_secs = sbt / SBT_1S; + + wd_last_sbt = sbt; } - if ((utim & WD_INTERVAL) == WD_TO_NEVER) { - utim = 0; - /* Assume all is well; watchdog signals failure. */ - error = 0; - } else { - /* Assume no watchdog available; watchdog flags success */ + if (sbt != 0) error = EOPNOTSUPP; - } + if (wd_softtimer) { - if (utim == 0) { + if (sbt == 0) { callout_stop(&wd_softtimeo_handle); } else { - (void) callout_reset(&wd_softtimeo_handle, - pow2ns_to_ticks(utim), wd_timeout_cb, "soft"); + (void) callout_reset_sbt(&wd_softtimeo_handle, + sbt, 0, wd_timeout_cb, "soft", 0); } error = 0; } else { - EVENTHANDLER_INVOKE(watchdog_list, utim, &error); + EVENTHANDLER_INVOKE(watchdog_sbt_list, sbt, &error_sbt, &error); + EVENTHANDLER_INVOKE(watchdog_list, pow2ns, &error); } /* - * If we no hardware watchdog responded, we have not tried to + * If no hardware watchdog responded, we have not tried to * attach an external software watchdog, and one is available, * attach it now and retry. */ - if (error == EOPNOTSUPP && first && *wdog_software_attach != NULL) { + if (error == EOPNOTSUPP && first && wdog_software_attach != NULL) { (*wdog_software_attach)(); - EVENTHANDLER_INVOKE(watchdog_list, utim, &error); + EVENTHANDLER_INVOKE(watchdog_sbt_list, sbt, &error_sbt, &error); + EVENTHANDLER_INVOKE(watchdog_list, pow2ns, &error); } - first = 0; + first = false; + /* TODO: Print a (rate limited?) warning if error_sbt is too far away */ wd_set_pretimeout(wd_pretimeout, true); - /* - * If we were able to arm/strobe the watchdog, then - * update the last time it was strobed for WDIOC_GETTIMELEFT - */ if (!error) { struct timespec ts; @@ -189,6 +191,7 @@ wdog_kern_pat(u_int utim) wd_lastpat_valid = 1; } } + return (error); } @@ -265,16 +268,14 @@ wd_timeout_cb(void *arg) * current actual watchdog timeout. */ static int -wd_set_pretimeout(int newtimeout, int disableiftoolong) +wd_set_pretimeout(sbintime_t newtimeout, int disableiftoolong) { - u_int utime; - struct timespec utime_ts; - int timeout_ticks; + sbintime_t utime; + sbintime_t timeout_left; - utime = wdog_kern_last_timeout(); - pow2ns_to_ts(utime, &utime_ts); + utime = wdog_kern_last_timeout_sbt(); /* do not permit a pre-timeout >= than the timeout. */ - if (newtimeout >= utime_ts.tv_sec) { + if (newtimeout >= utime) { /* * If 'disableiftoolong' then just fall through * so as to disable the pre-watchdog @@ -292,7 +293,7 @@ wd_set_pretimeout(int newtimeout, int disableiftoolong) return 0; } - timeout_ticks = pow2ns_to_ticks(utime) - (hz*newtimeout); + timeout_left = utime - newtimeout; #if 0 printf("wd_set_pretimeout: " "newtimeout: %d, " @@ -306,8 +307,8 @@ wd_set_pretimeout(int newtimeout, int disableiftoolong) #endif /* We determined the value is sane, so reset the callout */ - (void) callout_reset(&wd_pretimeo_handle, - timeout_ticks, wd_timeout_cb, "pre"); + (void) callout_reset_sbt(&wd_pretimeo_handle, + timeout_left, 0, wd_timeout_cb, "pre", 0); wd_pretimeout = newtimeout; return 0; } @@ -316,6 +317,7 @@ static int wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags __unused, struct thread *td) { + sbintime_t sb; u_int u; time_t timeleft; int error; @@ -351,29 +353,55 @@ wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, error = EINVAL; } break; - case WDIOC_GETPRETIMEOUT: - *(int *)data = (int)wd_pretimeout; +#ifdef COMPAT_FREEBSD14 + case WDIOC_GETPRETIMEOUT_14: + *(int *)data = (int)(wd_pretimeout / SBT_1S); break; - case WDIOC_SETPRETIMEOUT: - error = wd_set_pretimeout(*(int *)data, false); + case WDIOC_SETPRETIMEOUT_14: + error = wd_set_pretimeout(*(int *)data * SBT_1S, false); break; - case WDIOC_GETTIMELEFT: + case WDIOC_GETTIMELEFT_14: error = wd_get_time_left(td, &timeleft); if (error) break; *(int *)data = (int)timeleft; break; - case WDIOC_SETTIMEOUT: + case WDIOC_SETTIMEOUT_14: u = *(u_int *)data; - error = wdog_kern_pat(seconds_to_pow2ns(u)); + error = wdog_kern_pat_sbt(mstosbt(u * 1000ULL)); break; - case WDIOC_GETTIMEOUT: + case WDIOC_GETTIMEOUT_14: u = wdog_kern_last_timeout(); *(u_int *)data = u; break; - case WDIOCPATPAT: + case WDIOCPATPAT_14: error = wd_ioctl_patpat(data); break; +#endif + + /* New API */ + case WDIOC_CONTROL: + wdog_control(*(int *)data); + break; + case WDIOC_SETTIMEOUT: + sb = *(sbintime_t *)data; + error = wdog_kern_pat_sbt(sb); + break; + case WDIOC_GETTIMEOUT: + *(sbintime_t *)data = wdog_kern_last_timeout_sbt(); + break; + case WDIOC_GETTIMELEFT: + error = wd_get_time_left(td, &timeleft); + if (error) + break; + *(sbintime_t *)data = (sbintime_t)timeleft * SBT_1S; + break; + case WDIOC_GETPRETIMEOUT: + *(sbintime_t *)data = wd_pretimeout; + break; + case WDIOC_SETPRETIMEOUT: + error = wd_set_pretimeout(*(sbintime_t *)data, false); + break; default: error = ENOIOCTL; break; @@ -392,6 +420,12 @@ wdog_kern_last_timeout(void) return (wd_last_u); } +sbintime_t +wdog_kern_last_timeout_sbt(void) +{ + return (wd_last_sbt); +} + static struct cdevsw wd_cdevsw = { .d_version = D_VERSION, .d_ioctl = wd_ioctl, diff --git a/sys/fs/cd9660/cd9660_vnops.c b/sys/fs/cd9660/cd9660_vnops.c index c4d0e6ba7b30..a496b41fcf6e 100644 --- a/sys/fs/cd9660/cd9660_vnops.c +++ b/sys/fs/cd9660/cd9660_vnops.c @@ -124,7 +124,7 @@ cd9660_access(struct vop_access_args *ap) uid_t uid; gid_t gid; - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); /* @@ -162,7 +162,7 @@ cd9660_open(struct vop_open_args *ap) struct vnode *vp = ap->a_vp; struct iso_node *ip = VTOI(vp); - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); vnode_create_vobject(vp, ip->i_size, ap->a_td); @@ -242,7 +242,7 @@ cd9660_ioctl(struct vop_ioctl_args *ap) VOP_UNLOCK(vp); return (EBADF); } - if (vp->v_type == VCHR || vp->v_type == VBLK) { + if (VN_ISDEV(vp)) { VOP_UNLOCK(vp); return (EOPNOTSUPP); } @@ -280,7 +280,7 @@ cd9660_read(struct vop_read_args *ap) int seqcount; long size, n, on; - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); seqcount = ap->a_ioflag >> IO_SEQSHIFT; @@ -711,7 +711,7 @@ cd9660_strategy(struct vop_strategy_args *ap) struct bufobj *bo; ip = VTOI(vp); - if (vp->v_type == VBLK || vp->v_type == VCHR) + if (VN_ISDEV(vp)) panic("cd9660_strategy: spec"); if (bp->b_blkno == bp->b_lblkno) { bp->b_blkno = (ip->iso_start + bp->b_lblkno) << @@ -818,7 +818,7 @@ cd9660_getpages(struct vop_getpages_args *ap) struct vnode *vp; vp = ap->a_vp; - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); if (use_buf_pager) diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c index 064c10bd18b2..00389c927087 100644 --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/sys/fs/ext2fs/ext2_vnops.c @@ -222,7 +222,7 @@ ext2_itimes_locked(struct vnode *vp) ip = VTOI(vp); if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) return; - if ((vp->v_type == VBLK || vp->v_type == VCHR)) + if (VN_ISDEV(vp)) ip->i_flag |= IN_LAZYMOD; else ip->i_flag |= IN_MODIFIED; @@ -276,7 +276,7 @@ static int ext2_open(struct vop_open_args *ap) { - if (ap->a_vp->v_type == VBLK || ap->a_vp->v_type == VCHR) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); /* @@ -360,7 +360,7 @@ ext2_getattr(struct vop_getattr_args *ap) vap->va_nlink = ip->i_nlink; vap->va_uid = ip->i_uid; vap->va_gid = ip->i_gid; - vap->va_rdev = ip->i_rdev; + vap->va_rdev = VN_ISDEV(vp) ? ip->i_rdev : NODEV; vap->va_size = ip->i_size; vap->va_atime.tv_sec = ip->i_atime; vap->va_atime.tv_nsec = E2DI_HAS_XTIME(ip) ? ip->i_atimensec : 0; @@ -1571,7 +1571,7 @@ ext2_strategy(struct vop_strategy_args *ap) daddr_t blkno; int error; - if (vp->v_type == VBLK || vp->v_type == VCHR) + if (VN_ISDEV(vp)) panic("ext2_strategy: spec"); if (bp->b_blkno == bp->b_lblkno) { if (VTOI(ap->a_vp)->i_flag & IN_E4EXTENTS) @@ -1733,7 +1733,7 @@ ext2_deleteextattr(struct vop_deleteextattr_args *ap) if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) return (EOPNOTSUPP); - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, @@ -1771,7 +1771,7 @@ ext2_getextattr(struct vop_getextattr_args *ap) if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) return (EOPNOTSUPP); - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, @@ -1814,7 +1814,7 @@ ext2_listextattr(struct vop_listextattr_args *ap) if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) return (EOPNOTSUPP); - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, @@ -1855,7 +1855,7 @@ ext2_setextattr(struct vop_setextattr_args *ap) if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) return (EOPNOTSUPP); - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index b782146b7278..de60a4717dd4 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -1748,7 +1748,7 @@ fuse_vnop_open(struct vop_open_args *ap) if (fuse_isdeadfs(vp)) return (EXTERROR(ENXIO, "This FUSE session is about " "to be closed")); - if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO) + if (VN_ISDEV(vp) || vp->v_type == VFIFO) return (EXTERROR(EOPNOTSUPP, "Unsupported vnode type", vp->v_type)); if ((a_mode & (FREAD | FWRITE | FEXEC)) == 0) diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c index 0ae3b94bef89..1e4e8506790f 100644 --- a/sys/fs/nfs/nfs_commonkrpc.c +++ b/sys/fs/nfs/nfs_commonkrpc.c @@ -239,6 +239,7 @@ static bool nfscl_use_gss[NFSV42_NPROCS] = { true, true, true, + true, }; /* diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 67e33193ecec..7f5b29ca2085 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -187,7 +187,7 @@ struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = { { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Read Plus */ { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Seek */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Write Same */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */ + { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Clone */ { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */ { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */ { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */ @@ -219,7 +219,7 @@ NFSD_VNET_DEFINE_STATIC(u_char *, nfsrv_dnsname) = NULL; static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }; + 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }; /* local functions */ static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); @@ -310,6 +310,7 @@ static struct { { NFSV4OP_LAYOUTERROR, 1, "LayoutError", 11, }, { NFSV4OP_VERIFY, 3, "AppendWrite", 11, }, { NFSV4OP_OPENATTR, 3, "OpenAttr", 8, }, + { NFSV4OP_SAVEFH, 5, "Clone", 5, }, }; /* @@ -319,7 +320,7 @@ static int nfs_bigrequest[NFSV42_NPROCS] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 1, 0 + 0, 1, 0, 0 }; /* @@ -648,7 +649,7 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap, NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE); (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0, &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL, - false, false, false); + false, false, false, 0); break; } } @@ -1302,7 +1303,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp, struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp, u_int32_t *leasep, u_int32_t *rderrp, bool *has_namedattrp, - NFSPROC_T *p, struct ucred *cred) + uint32_t *clone_blksizep, NFSPROC_T *p, struct ucred *cred) { u_int32_t *tl; int i = 0, j, k, l = 0, m, bitpos, attrsum = 0; @@ -1437,6 +1438,13 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_SYSTEM); } + /* Some filesystems do not support block cloning */ + if (vp == NULL || VOP_PATHCONF(vp, + _PC_CLONE_BLKSIZE, &has_pathconf) != 0) + has_pathconf = 0; + if (has_pathconf == 0) + NFSCLRBIT_ATTRBIT(&checkattrbits, + NFSATTRBIT_CLONEBLKSIZE); if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) || retnotsup) *retcmpp = NFSERR_NOTSAME; @@ -2374,6 +2382,23 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, if (compare && !(*retcmpp) && i != nfs_srvmaxio) *retcmpp = NFSERR_NOTSAME; break; + case NFSATTRBIT_CLONEBLKSIZE: + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (vp == NULL || VOP_PATHCONF(vp, + _PC_CLONE_BLKSIZE, &has_pathconf) + != 0) + has_pathconf = 0; + if (has_pathconf != + fxdr_unsigned(uint32_t, *tl)) + *retcmpp = NFSERR_NOTSAME; + } + } else if (clone_blksizep != NULL) { + *clone_blksizep = fxdr_unsigned(uint32_t, *tl); + } + attrsum += NFSX_UNSIGNED; + break; case NFSATTRBIT_CHANGEATTRTYPE: NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); if (compare) { @@ -2648,7 +2673,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno, struct statfs *pnfssf, bool xattrsupp, bool has_hiddensystem, - bool has_namedattr) + bool has_namedattr, uint32_t clone_blksize) { int bitpos, retnum = 0; u_int32_t *tl; @@ -2771,6 +2796,9 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN); NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM); } + if (clone_blksize == 0) + NFSCLRBIT_ATTRBIT(&attrbits, + NFSATTRBIT_CLONEBLKSIZE); retnum += nfsrv_putattrbit(nd, &attrbits); break; case NFSATTRBIT_TYPE: @@ -3249,6 +3277,11 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, } retnum += NFSX_UNSIGNED; break; + case NFSATTRBIT_CLONEBLKSIZE: + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(clone_blksize); + retnum += NFSX_UNSIGNED; + break; default: printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); } diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 54f60a753c50..61083ecf2d66 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -286,6 +286,8 @@ int nfsrvd_deallocate(struct nfsrv_descript *, int, vnode_t, struct nfsexstuff *); int nfsrvd_copy_file_range(struct nfsrv_descript *, int, vnode_t, vnode_t, struct nfsexstuff *, struct nfsexstuff *); +int nfsrvd_clone(struct nfsrv_descript *, int, + vnode_t, vnode_t, struct nfsexstuff *, struct nfsexstuff *); int nfsrvd_seek(struct nfsrv_descript *, int, vnode_t, struct nfsexstuff *); int nfsrvd_getxattr(struct nfsrv_descript *, int, @@ -341,7 +343,8 @@ int nfsv4_loadattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, struct nfsfh **, fhandle_t *, int, struct nfsv3_pathconf *, struct statfs *, struct nfsstatfs *, struct nfsfsinfo *, NFSACL_T *, - int, int *, u_int32_t *, u_int32_t *, bool *, NFSPROC_T *, struct ucred *); + int, int *, u_int32_t *, u_int32_t *, bool *, uint32_t *, NFSPROC_T *, + struct ucred *); int nfsv4_lock(struct nfsv4lock *, int, int *, struct mtx *, struct mount *); void nfsv4_unlock(struct nfsv4lock *, int); void nfsv4_relref(struct nfsv4lock *); @@ -397,7 +400,7 @@ void nfsrv_wcc(struct nfsrv_descript *, int, struct nfsvattr *, int, int nfsv4_fillattr(struct nfsrv_descript *, struct mount *, vnode_t, NFSACL_T *, struct vattr *, fhandle_t *, int, nfsattrbit_t *, struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t, struct statfs *, bool, bool, - bool); + bool, uint32_t); void nfsrv_fillattr(struct nfsrv_descript *, struct nfsvattr *); struct mbuf *nfsrv_adj(struct mbuf *, int, int); void nfsrv_postopattr(struct nfsrv_descript *, int, struct nfsvattr *); @@ -517,10 +520,10 @@ int nfsrpc_lock(struct nfsrv_descript *, struct nfsmount *, vnode_t, u_int8_t *, int, struct nfscllockowner *, int, int, u_int64_t, u_int64_t, short, struct ucred *, NFSPROC_T *, int); int nfsrpc_statfs(vnode_t, struct nfsstatfs *, struct nfsfsinfo *, uint32_t *, - struct ucred *, NFSPROC_T *, struct nfsvattr *, int *); + uint32_t *, struct ucred *, NFSPROC_T *, struct nfsvattr *, int *); int nfsrpc_fsinfo(vnode_t, struct nfsfsinfo *, struct ucred *, NFSPROC_T *, struct nfsvattr *, int *); -int nfsrpc_pathconf(vnode_t, struct nfsv3_pathconf *, bool *, +int nfsrpc_pathconf(vnode_t, struct nfsv3_pathconf *, bool *, uint32_t *, struct ucred *, NFSPROC_T *, struct nfsvattr *, int *); int nfsrpc_renew(struct nfsclclient *, struct nfsclds *, struct ucred *, NFSPROC_T *); @@ -562,6 +565,8 @@ int nfsrpc_deallocate(vnode_t, off_t, off_t, struct nfsvattr *, int *, int nfsrpc_copy_file_range(vnode_t, off_t *, vnode_t, off_t *, size_t *, unsigned int, int *, struct nfsvattr *, int *, struct nfsvattr *, struct ucred *, bool, bool *); +int nfsrpc_clone(vnode_t, off_t *, vnode_t, off_t *, size_t *, bool, + int *, struct nfsvattr *, int *, struct nfsvattr *, struct ucred *); int nfsrpc_seek(vnode_t, off_t *, bool *, int, struct ucred *, struct nfsvattr *, int *); int nfsrpc_getextattr(vnode_t, const char *, struct uio *, ssize_t *, @@ -668,7 +673,7 @@ int nfscl_nget(mount_t, vnode_t, struct nfsfh *, NFSPROC_T *nfscl_getparent(NFSPROC_T *); void nfscl_start_renewthread(struct nfsclclient *); void nfscl_loadsbinfo(struct nfsmount *, struct nfsstatfs *, void *); -void nfscl_loadfsinfo (struct nfsmount *, struct nfsfsinfo *); +void nfscl_loadfsinfo(struct nfsmount *, struct nfsfsinfo *, uint32_t); void nfscl_delegreturn(struct nfscldeleg *, int, struct nfsmount *, struct ucred *, NFSPROC_T *); void nfsrvd_cbinit(int); @@ -737,7 +742,7 @@ int nfsvno_updfilerev(vnode_t, struct nfsvattr *, struct nfsrv_descript *, int nfsvno_fillattr(struct nfsrv_descript *, struct mount *, vnode_t, struct nfsvattr *, fhandle_t *, int, nfsattrbit_t *, struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t, bool, bool, - bool); + bool, uint32_t); int nfsrv_sattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, nfsattrbit_t *, NFSACL_T *, NFSPROC_T *); int nfsv4_sattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, nfsattrbit_t *, diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h index c30b46261df0..bd6107187966 100644 --- a/sys/fs/nfs/nfsport.h +++ b/sys/fs/nfs/nfsport.h @@ -442,10 +442,13 @@ /* Do a NFSv4 Openattr. */ #define NFSPROC_OPENATTR 70 +/* Do a NFSv4.2 Clone. */ +#define NFSPROC_CLONE 71 + /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 71 +#define NFSV42_NPROCS 72 /* Value of NFSV42_NPROCS for old nfsstats structure. (Always 69) */ #define NFSV42_OLDNPROCS 69 @@ -477,7 +480,7 @@ struct nfsstatsv1 { uint64_t readlink_bios; uint64_t biocache_readdirs; uint64_t readdir_bios; - uint64_t rpccnt[NFSV42_NPROCS + 9]; + uint64_t rpccnt[NFSV42_NPROCS + 8]; uint64_t rpcretries; uint64_t srvrpccnt[NFSV42_NOPS + NFSV4OP_FAKENOPS + 15]; uint64_t srvlayouts; diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h index cb5a80e8df73..d628108bdc1a 100644 --- a/sys/fs/nfs/nfsproto.h +++ b/sys/fs/nfs/nfsproto.h @@ -411,10 +411,13 @@ /* Do a NFSv4 Openattr. */ #define NFSPROC_OPENATTR 70 +/* Do a NFSv4.2 Clone. */ +#define NFSPROC_CLONE 71 + /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 71 +#define NFSV42_NPROCS 72 /* Value of NFSV42_NPROCS for old nfsstats structure. (Always 69) */ #define NFSV42_OLDNPROCS 69 @@ -1194,6 +1197,7 @@ struct nfsv3_sattr { NFSATTRBM_LAYOUTBLKSIZE | \ NFSATTRBM_LAYOUTALIGNMENT | \ NFSATTRBM_SUPPATTREXCLCREAT | \ + NFSATTRBM_CLONEBLKSIZE | \ NFSATTRBM_CHANGEATTRTYPE | \ NFSATTRBM_XATTRSUPPORT) @@ -1242,7 +1246,8 @@ struct nfsv3_sattr { * NFSATTRBIT_NFSV42 - Attributes only supported by NFSv4.2. */ #define NFSATTRBIT_NFSV42_2 \ - (NFSATTRBM_CHANGEATTRTYPE | \ + (NFSATTRBM_CLONEBLKSIZE | \ + NFSATTRBM_CHANGEATTRTYPE | \ NFSATTRBM_XATTRSUPPORT | \ NFSATTRBM_MODEUMASK) @@ -1415,7 +1420,7 @@ struct nfsv3_sattr { /* * NFSGETATTRBIT_STATFS2 - bits 64<->95 */ -#define NFSGETATTRBIT_STATFS2 0 +#define NFSGETATTRBIT_STATFS2 (NFSATTRBM_CLONEBLKSIZE) /* * Set of attributes for the equivalent of an nfsv3 pathconf rpc. @@ -1438,7 +1443,7 @@ struct nfsv3_sattr { /* * NFSGETATTRBIT_PATHCONF2 - bits 64<->95 */ -#define NFSGETATTRBIT_PATHCONF2 0 +#define NFSGETATTRBIT_PATHCONF2 (NFSATTRBM_CLONEBLKSIZE) /* * Sets of attributes required by readdir and readdirplus. diff --git a/sys/fs/nfsclient/nfs_clcomsubs.c b/sys/fs/nfsclient/nfs_clcomsubs.c index bca0bdcd0df1..05963074e53d 100644 --- a/sys/fs/nfsclient/nfs_clcomsubs.c +++ b/sys/fs/nfsclient/nfs_clcomsubs.c @@ -272,7 +272,7 @@ nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap) if (nd->nd_flag & ND_NFSV4) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, - NULL); + NULL, NULL); } else if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR); nap->na_type = nfsv34tov_type(fp->fa_type); diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index b25d967982a1..704aeeeabdf2 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -828,7 +828,7 @@ nfscl_wcc_data(struct nfsrv_descript *nd, struct vnode *vp, == (ND_NFSV4 | ND_V4WCCATTR)) { error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (error) return (error); /* @@ -963,7 +963,8 @@ nfscl_loadsbinfo(struct nfsmount *nmp, struct nfsstatfs *sfp, void *statfs) * Use the fsinfo stuff to update the mount point. */ void -nfscl_loadfsinfo(struct nfsmount *nmp, struct nfsfsinfo *fsp) +nfscl_loadfsinfo(struct nfsmount *nmp, struct nfsfsinfo *fsp, + uint32_t clone_blksize) { if ((nmp->nm_wsize == 0 || fsp->fs_wtpref < nmp->nm_wsize) && @@ -1003,6 +1004,14 @@ nfscl_loadfsinfo(struct nfsmount *nmp, struct nfsfsinfo *fsp) fsp->fs_maxfilesize < nmp->nm_maxfilesize) nmp->nm_maxfilesize = fsp->fs_maxfilesize; nmp->nm_mountp->mnt_stat.f_iosize = newnfs_iosize(nmp); + + /* + * Although ZFS reports a clone_blksize of 16Mbytes, + * 128Kbytes usually works, so set it to that. + */ + if (clone_blksize > 128 * 1024) + clone_blksize = 128 * 1024; + nmp->nm_cloneblksize = clone_blksize; nmp->nm_state |= NFSSTA_GOTFSINFO; } diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 920fcf7b8c61..4ec621de2eff 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -225,6 +225,9 @@ static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *, static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, size_t *, nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *, struct nfsvattr *, int *, bool, int *, struct ucred *, NFSPROC_T *); +static int nfsrpc_clonerpc(vnode_t, off_t, vnode_t, off_t, size_t *, bool, + nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *, + struct nfsvattr *, int *, struct ucred *, NFSPROC_T *); static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *, int, struct nfsvattr *, int *, struct ucred *); static struct mbuf *nfsm_split(struct mbuf *, uint64_t); @@ -696,7 +699,7 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, ("nfsrpc_openrpc: Getattr repstat")); error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, NULL, NULL, p, cred); if (error) goto nfsmout; } @@ -1355,7 +1358,7 @@ nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred, if ((nd->nd_flag & ND_NFSV4) != 0) error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); else error = nfsm_loadattr(nd, nap); } else @@ -3597,7 +3600,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, nfsva.na_mntonfileno = UINT64_MAX; error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, NULL, NULL, p, cred); if (error) { dotdotfileid = dotfileid; } else if (gotmnton) { @@ -3847,7 +3850,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, nfsva.na_mntonfileno = UINT64_MAX; error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, &rderr, NULL, p, cred); + NULL, NULL, &rderr, NULL, NULL, p, cred); if (error) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); @@ -4072,7 +4075,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, nfsva.na_mntonfileno = UINT64_MAX; error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, NULL, NULL, p, cred); if (error) { dotdotfileid = dotfileid; } else if (gotmnton) { @@ -4346,7 +4349,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, nfsva.na_mntonfileno = 0xffffffff; error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, &rderr, NULL, p, cred); + NULL, NULL, &rderr, NULL, NULL, p, cred); if (error) goto nfsmout; } @@ -4981,8 +4984,8 @@ nfsmout: */ int nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, - uint32_t *leasep, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, - int *attrflagp) + uint32_t *leasep, uint32_t *cloneblksizep, struct ucred *cred, NFSPROC_T *p, + struct nfsvattr *nap, int *attrflagp) { u_int32_t *tl = NULL; struct nfsrv_descript nfsd, *nd = &nfsd; @@ -4991,6 +4994,8 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, int error; *attrflagp = 0; + if (cloneblksizep != NULL) + *cloneblksizep = 0; nmp = VFSTONFS(vp->v_mount); if (NFSHASNFSV4(nmp)) { /* @@ -5009,7 +5014,7 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, if (nd->nd_repstat == 0) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL, - NULL, p, cred); + NULL, cloneblksizep, p, cred); if (!error) { nmp->nm_fsid[0] = nap->na_filesid[0]; nmp->nm_fsid[1] = nap->na_filesid[1]; @@ -5063,7 +5068,8 @@ nfsmout: */ int nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp, - struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) + uint32_t *clone_blksizep, struct ucred *cred, NFSPROC_T *p, + struct nfsvattr *nap, int *attrflagp) { struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp; @@ -5074,6 +5080,7 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp, *has_namedattrp = false; *attrflagp = 0; + *clone_blksizep = 0; nmp = VFSTONFS(vp->v_mount); if (NFSHASNFSV4(nmp)) { np = VTONFS(vp); @@ -5100,7 +5107,7 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp, if (nd->nd_repstat == 0) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, - has_namedattrp, p, cred); + has_namedattrp, clone_blksizep, p, cred); if (!error) *attrflagp = 1; } else { @@ -5395,7 +5402,8 @@ nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp) return (error); if (!nd->nd_repstat) error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, - NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, NULL, NULL, p, + cred); else error = nd->nd_repstat; m_freem(nd->nd_mrep); @@ -5437,7 +5445,7 @@ nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); (void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0, &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL, false, false, - false); + false, 0); error = nfscl_request(nd, vp, p, cred); if (error) return (error); @@ -8496,7 +8504,7 @@ nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, if (*++tl == 0) { error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, NULL, NULL, p, cred); if (error != 0) goto nfsmout; if (ndp != NULL) { @@ -9168,6 +9176,199 @@ nfsmout: } /* + * nfs clone operation. + */ +int +nfsrpc_clone(vnode_t invp, off_t *inoffp, vnode_t outvp, + off_t *outoffp, size_t *lenp, bool toeof, int *inattrflagp, + struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap, + struct ucred *cred) +{ + int error, expireret = 0, retrycnt; + uint32_t clidrev = 0; + struct nfsmount *nmp = VFSTONFS(invp->v_mount); + struct nfsfh *innfhp = NULL, *outnfhp = NULL; + nfsv4stateid_t instateid, outstateid; + void *inlckp, *outlckp; + + if (nmp->nm_clp != NULL) + clidrev = nmp->nm_clp->nfsc_clientidrev; + innfhp = VTONFS(invp)->n_fhp; + outnfhp = VTONFS(outvp)->n_fhp; + retrycnt = 0; + do { + /* Get both stateids. */ + inlckp = NULL; + nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len, + NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid, + &inlckp); + outlckp = NULL; + nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len, + NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid, + &outlckp); + + error = nfsrpc_clonerpc(invp, *inoffp, outvp, *outoffp, lenp, + toeof, &instateid, &outstateid, innap, inattrflagp, outnap, + outattrflagp, cred, curthread); + if (error == 0) { + *inoffp += *lenp; + *outoffp += *lenp; + } else if (error == NFSERR_STALESTATEID) + nfscl_initiate_recovery(nmp->nm_clp); + if (inlckp != NULL) + nfscl_lockderef(inlckp); + if (outlckp != NULL) + nfscl_lockderef(outlckp); + if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || + error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || + error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { + (void) nfs_catnap(PZERO, error, "nfs_cfr"); + } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && + error == NFSERR_BADSTATEID)) && clidrev != 0) { + expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, + curthread); + } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) { + error = EIO; + } + retrycnt++; + } while (error == NFSERR_GRACE || error == NFSERR_DELAY || + error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || + error == NFSERR_STALEDONTRECOVER || + (error == NFSERR_OLDSTATEID && retrycnt < 20) || + ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && + expireret == 0 && clidrev != 0 && retrycnt < 4)); + if (error != 0 && (retrycnt >= 4 || + error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || + error == NFSERR_STALEDONTRECOVER)) + error = EIO; + return (error); +} + +/* + * The clone RPC. + */ +static int +nfsrpc_clonerpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff, + size_t *lenp, bool toeof, nfsv4stateid_t *instateidp, + nfsv4stateid_t *outstateidp, struct nfsvattr *innap, int *inattrflagp, + struct nfsvattr *outnap, int *outattrflagp, struct ucred *cred, + NFSPROC_T *p) +{ + uint32_t *tl, *opcntp; + int error; + struct nfsrv_descript nfsd; + struct nfsrv_descript *nd = &nfsd; + struct nfsmount *nmp; + nfsattrbit_t attrbits; + struct vattr va; + uint64_t len; + + nmp = VFSTONFS(invp->v_mount); + *inattrflagp = *outattrflagp = 0; + len = *lenp; + if (len == 0) + return (0); + if (toeof) + len = 0; + nfscl_reqstart(nd, NFSPROC_CLONE, nmp, VTONFS(invp)->n_fhp->nfh_fh, + VTONFS(invp)->n_fhp->nfh_len, &opcntp, NULL, 0, 0, cred); + /* + * First do a Setattr of atime to the server's clock + * time. The FreeBSD "collective" was of the opinion + * that setting atime was necessary for this syscall. + * Do the Setattr before the Clone, so that it can be + * handled well if the server replies NFSERR_DELAY to + * the Setattr operation. + */ + if ((nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) { + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_SETATTR); + nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID); + VATTR_NULL(&va); + va.va_atime.tv_sec = va.va_atime.tv_nsec = 0; + va.va_vaflags = VA_UTIMES_NULL; + nfscl_fillsattr(nd, &va, invp, 0, 0); + /* Bump opcnt from 7 to 8. */ + *opcntp = txdr_unsigned(8); + } + + /* Now Getattr the invp attributes. */ + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + NFSGETATTR_ATTRBIT(&attrbits); + nfsrv_putattrbit(nd, &attrbits); + + /* Set outvp. */ + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_PUTFH); + (void)nfsm_fhtom(nmp, nd, VTONFS(outvp)->n_fhp->nfh_fh, + VTONFS(outvp)->n_fhp->nfh_len, 0); + + /* Do the Clone. */ + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_CLONE); + nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID); + nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID); + NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + NFSX_UNSIGNED); + txdr_hyper(inoff, tl); tl += 2; + txdr_hyper(outoff, tl); tl += 2; + txdr_hyper(len, tl); tl += 2; + + /* Get the outvp attributes. */ + *tl = txdr_unsigned(NFSV4OP_GETATTR); + NFSWRITEGETATTR_ATTRBIT(&attrbits); + nfsrv_putattrbit(nd, &attrbits); + + error = nfscl_request(nd, invp, p, cred); + if (error != 0) + return (error); + /* Skip over the Setattr reply. */ + if ((nd->nd_flag & ND_NOMOREDATA) == 0 && + (nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*(tl + 1) == 0) { + error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); + if (error != 0) + goto nfsmout; + } else + nd->nd_flag |= ND_NOMOREDATA; + } + if ((nd->nd_flag & ND_NOMOREDATA) == 0) { + /* Get the input file's attributes. */ + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*(tl + 1) == 0) { + error = nfsm_loadattr(nd, innap); + if (error != 0) + goto nfsmout; + *inattrflagp = 1; + } else + nd->nd_flag |= ND_NOMOREDATA; + } + /* Skip over return stat for PutFH. */ + if ((nd->nd_flag & ND_NOMOREDATA) == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*++tl != 0) + nd->nd_flag |= ND_NOMOREDATA; + } + /* Skip over return stat for Clone. */ + if ((nd->nd_flag & ND_NOMOREDATA) == 0) + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (nd->nd_repstat == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + error = nfsm_loadattr(nd, outnap); + if (error == 0) + *outattrflagp = NFS_LATTR_NOSHRINK; + } else { + *lenp = 0; + } + if (error == 0) + error = nd->nd_repstat; +nfsmout: + m_freem(nd->nd_mrep); + return (error); +} + +/* * Seek operation. */ int @@ -9724,13 +9925,13 @@ nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td) struct nfsstatfs sb; struct mount *mp; struct nfsmount *nmp; - uint32_t lease; + uint32_t clone_blksize, lease; int attrflag, error; mp = vp->v_mount; nmp = VFSTONFS(mp); - error = nfsrpc_statfs(vp, &sb, &fs, &lease, cred, td, &nfsva, - &attrflag); + error = nfsrpc_statfs(vp, &sb, &fs, &lease, &clone_blksize, cred, td, + &nfsva, &attrflag); if (attrflag != 0) (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error == 0) { @@ -9739,7 +9940,7 @@ nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td) nmp->nm_clp->nfsc_renew = NFSCL_RENEW(lease); NFSUNLOCKCLSTATE(); mtx_lock(&nmp->nm_mtx); - nfscl_loadfsinfo(nmp, &fs); + nfscl_loadfsinfo(nmp, &fs, clone_blksize); nfscl_loadsbinfo(nmp, &sb, &mp->mnt_stat); mp->mnt_stat.f_iosize = newnfs_iosize(nmp); mtx_unlock(&nmp->nm_mtx); diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c index 99a781640c53..aa9d01fc4632 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -3701,7 +3701,7 @@ nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p) if (!error) (void) nfsv4_fillattr(nd, NULL, NULL, NULL, &va, NULL, 0, &rattrbits, NULL, p, 0, 0, 0, 0, - (uint64_t)0, NULL, false, false, false); + (uint64_t)0, NULL, false, false, false, 0); break; case NFSV4OP_CBRECALL: NFSCL_DEBUG(4, "cbrecall\n"); diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index 0bd05c03885b..5ea7eab07632 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -292,8 +292,10 @@ nfs_statfs(struct mount *mp, struct statfs *sbp) int error = 0, attrflag, gotfsinfo = 0, ret; struct nfsnode *np; char *fakefh; + uint32_t clone_blksize; td = curthread; + clone_blksize = 0; error = vfs_busy(mp, MBF_NOWAIT); if (error) @@ -337,8 +339,8 @@ nfs_statfs(struct mount *mp, struct statfs *sbp) } else mtx_unlock(&nmp->nm_mtx); if (!error) - error = nfsrpc_statfs(vp, &sb, &fs, NULL, td->td_ucred, td, - &nfsva, &attrflag); + error = nfsrpc_statfs(vp, &sb, &fs, NULL, &clone_blksize, + td->td_ucred, td, &nfsva, &attrflag); if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 && error == NFSERR_WRONGSEC) { /* Cannot get new stats, so return what is in mnt_stat. */ @@ -375,7 +377,7 @@ nfs_statfs(struct mount *mp, struct statfs *sbp) if (!error) { mtx_lock(&nmp->nm_mtx); if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) - nfscl_loadfsinfo(nmp, &fs); + nfscl_loadfsinfo(nmp, &fs, clone_blksize); nfscl_loadsbinfo(nmp, &sb, sbp); sbp->f_iosize = newnfs_iosize(nmp); mtx_unlock(&nmp->nm_mtx); @@ -408,7 +410,7 @@ ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, if (attrflag) (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); mtx_lock(&nmp->nm_mtx); - nfscl_loadfsinfo(nmp, &fs); + nfscl_loadfsinfo(nmp, &fs, 0); mtx_unlock(&nmp->nm_mtx); } return (error); diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index fa451887e73e..52f72dc43c3f 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -1782,7 +1782,7 @@ nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, int error = 0, attrflag, dattrflag; u_int32_t rdev; - if (vap->va_type == VCHR || vap->va_type == VBLK) + if (VATTR_ISDEV(vap)) rdev = vap->va_rdev; else if (vap->va_type == VFIFO || vap->va_type == VSOCK) rdev = 0xffffffff; @@ -4027,31 +4027,51 @@ nfs_copy_file_range(struct vop_copy_file_range_args *ap) struct vattr va, *vap; struct uio io; struct nfsmount *nmp; + struct nfsnode *np; size_t len, len2; ssize_t r; int error, inattrflag, outattrflag, ret, ret2, invp_lock; off_t inoff, outoff; - bool consecutive, must_commit, tryoutcred; + bool consecutive, must_commit, onevp, toeof, tryclone, tryoutcred; + bool mustclone; /* * NFSv4.2 Copy is not permitted for infile == outfile. + * The NFSv4.2 Clone operation does work on non-overlapping + * byte ranges in the same file, but only if offsets + * (and len if not to EOF) are aligned properly. * TODO: copy_file_range() between multiple NFS mountpoints + * --> This is not possible now, since each mount appears to + * the NFSv4.n server as a separate client. */ - if (invp == outvp || invp->v_mount != outvp->v_mount) { + if ((invp == outvp && (ap->a_flags & COPY_FILE_RANGE_CLONE) == 0) || + (invp != outvp && invp->v_mount != outvp->v_mount)) { generic_copy: return (ENOSYS); } - - invp_lock = LK_SHARED; + if (invp == outvp) { + onevp = true; + invp_lock = LK_EXCLUSIVE; + } else { + onevp = false; + invp_lock = LK_SHARED; + } + mustclone = false; + if (onevp || (ap->a_flags & COPY_FILE_RANGE_CLONE) != 0) + mustclone = true; relock: + inoff = *ap->a_inoffp; + outoff = *ap->a_outoffp; - /* Lock both vnodes, avoiding risk of deadlock. */ + /* Lock vnode(s), avoiding risk of deadlock. */ do { mp = NULL; error = vn_start_write(outvp, &mp, V_WAIT); if (error == 0) { error = vn_lock(outvp, LK_EXCLUSIVE); if (error == 0) { + if (onevp) + break; error = vn_lock(invp, invp_lock | LK_NOWAIT); if (error == 0) break; @@ -4071,16 +4091,24 @@ relock: return (error); /* - * More reasons to avoid nfs copy: not NFSv4.2, or explicitly - * disabled. + * More reasons to avoid nfs copy/clone: not NFSv4.2, explicitly + * disabled or requires cloning and unable to clone. + * Only clone if the clone_blksize attribute is supported + * and the clone_blksize is greater than 0. + * Alignment of offsets and length will be checked later. */ nmp = VFSTONFS(invp->v_mount); + np = VTONFS(invp); mtx_lock(&nmp->nm_mtx); + if ((nmp->nm_privflag & NFSMNTP_NOCOPY) != 0) + mustclone = true; if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION || - (nmp->nm_privflag & NFSMNTP_NOCOPY) != 0) { + (mustclone && (!NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, + NFSATTRBIT_CLONEBLKSIZE) || nmp->nm_cloneblksize == 0))) { mtx_unlock(&nmp->nm_mtx); VOP_UNLOCK(invp); - VOP_UNLOCK(outvp); + if (!onevp) + VOP_UNLOCK(outvp); /* For onevp, same as invp. */ if (mp != NULL) vn_finished_write(mp); goto generic_copy; @@ -4111,6 +4139,8 @@ relock: invp_obj = invp->v_object; if (invp_obj != NULL && vm_object_mightbedirty(invp_obj)) { if (invp_lock != LK_EXCLUSIVE) { + KASSERT(!onevp, ("nfs_copy_file_range: " + "invp_lock LK_SHARED for onevp")); invp_lock = LK_EXCLUSIVE; VOP_UNLOCK(invp); VOP_UNLOCK(outvp); @@ -4134,10 +4164,10 @@ relock: else consecutive = false; mtx_unlock(&nmp->nm_mtx); - inoff = *ap->a_inoffp; - outoff = *ap->a_outoffp; tryoutcred = true; must_commit = false; + toeof = false; + if (error == 0) { vap = &VTONFS(invp)->n_vattr.na_vattr; error = VOP_GETATTR(invp, vap, ap->a_incred); @@ -4169,29 +4199,63 @@ relock: if (error == 0 && ret != 0) error = ret; } - } else if (inoff + len > vap->va_size) + } else if (inoff + len >= vap->va_size) { + toeof = true; *ap->a_lenp = len = vap->va_size - inoff; + } } else error = 0; } /* + * For cloning, the offsets must be clone blksize aligned and + * the len must be blksize aligned unless it goes to EOF on + * the input file. + */ + tryclone = false; + if (len > 0) { + if (error == 0 && NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, + NFSATTRBIT_CLONEBLKSIZE) && nmp->nm_cloneblksize != 0 && + (inoff % nmp->nm_cloneblksize) == 0 && + (outoff % nmp->nm_cloneblksize) == 0 && + (toeof || (len % nmp->nm_cloneblksize) == 0)) + tryclone = true; + else if (mustclone) + error = ENOSYS; + } + + /* * len will be set to 0 upon a successful Copy RPC. - * As such, this only loops when the Copy RPC needs to be retried. + * As such, this only loops when the Copy/Clone RPC needs to be retried. */ while (len > 0 && error == 0) { inattrflag = outattrflag = 0; len2 = len; - if (tryoutcred) - error = nfsrpc_copy_file_range(invp, ap->a_inoffp, - outvp, ap->a_outoffp, &len2, ap->a_flags, - &inattrflag, &innfsva, &outattrflag, &outnfsva, - ap->a_outcred, consecutive, &must_commit); - else - error = nfsrpc_copy_file_range(invp, ap->a_inoffp, - outvp, ap->a_outoffp, &len2, ap->a_flags, - &inattrflag, &innfsva, &outattrflag, &outnfsva, - ap->a_incred, consecutive, &must_commit); + if (tryclone) { + if (tryoutcred) + error = nfsrpc_clone(invp, ap->a_inoffp, outvp, + ap->a_outoffp, &len2, toeof, &inattrflag, + &innfsva, &outattrflag, &outnfsva, + ap->a_outcred); + else + error = nfsrpc_clone(invp, ap->a_inoffp, outvp, + ap->a_outoffp, &len2, toeof, &inattrflag, + &innfsva, &outattrflag, &outnfsva, + ap->a_incred); + } else { + if (tryoutcred) + error = nfsrpc_copy_file_range(invp, + ap->a_inoffp, outvp, ap->a_outoffp, &len2, + ap->a_flags, &inattrflag, &innfsva, + &outattrflag, &outnfsva, + ap->a_outcred, consecutive, &must_commit); + else + error = nfsrpc_copy_file_range(invp, + ap->a_inoffp, outvp, ap->a_outoffp, &len2, + ap->a_flags, &inattrflag, &innfsva, + &outattrflag, &outnfsva, + ap->a_incred, consecutive, &must_commit); + } if (inattrflag != 0) ret = nfscl_loadattrcache(&invp, &innfsva, NULL, 0, 1); if (outattrflag != 0) @@ -4230,6 +4294,13 @@ relock: /* Try again with incred. */ tryoutcred = false; error = 0; + } else if (tryclone && error != 0) { + if (mustclone) { + error = ENOSYS; + } else { + tryclone = false; + error = 0; + } } if (error == NFSERR_STALEWRITEVERF) { /* @@ -4243,11 +4314,12 @@ relock: } } VOP_UNLOCK(invp); - VOP_UNLOCK(outvp); + if (!onevp) + VOP_UNLOCK(outvp); /* For onevp, same as invp. */ if (mp != NULL) vn_finished_write(mp); if (error == NFSERR_NOTSUPP || error == NFSERR_OFFLOADNOREQS || - error == NFSERR_ACCES) { + error == NFSERR_ACCES || error == ENOSYS) { /* * Unlike the NFSv4.2 Copy, vn_generic_copy_file_range() can * use a_incred for the read and a_outcred for the write, so @@ -4255,7 +4327,7 @@ relock: * For NFSERR_NOTSUPP and NFSERR_OFFLOADNOREQS, the Copy can * never succeed, so disable it. */ - if (error != NFSERR_ACCES) { + if (error != NFSERR_ACCES && error != ENOSYS) { /* Can never do Copy on this mount. */ mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NOCOPY; @@ -4596,6 +4668,7 @@ nfs_pathconf(struct vop_pathconf_args *ap) struct nfsmount *nmp; struct thread *td = curthread; off_t off; + uint32_t clone_blksize; bool eof, has_namedattr, named_enabled; int attrflag, error; struct nfsnode *np; @@ -4604,19 +4677,22 @@ nfs_pathconf(struct vop_pathconf_args *ap) np = VTONFS(vp); named_enabled = false; has_namedattr = false; + clone_blksize = 0; if ((NFS_ISV34(vp) && (ap->a_name == _PC_LINK_MAX || ap->a_name == _PC_NAME_MAX || ap->a_name == _PC_CHOWN_RESTRICTED || ap->a_name == _PC_NO_TRUNC)) || (NFS_ISV4(vp) && (ap->a_name == _PC_ACL_NFS4 || - ap->a_name == _PC_HAS_NAMEDATTR))) { + ap->a_name == _PC_HAS_NAMEDATTR || + ap->a_name == _PC_CLONE_BLKSIZE))) { /* * Since only the above 4 a_names are returned by the NFSv3 * Pathconf RPC, there is no point in doing it for others. * For NFSv4, the Pathconf RPC (actually a Getattr Op.) can - * be used for _PC_ACL_NFS4 and _PC_HAS_NAMEDATTR as well. + * be used for _PC_ACL_NFS4, _PC_HAS_NAMEDATTR and + * _PC_CLONE_BLKSIZE as well. */ - error = nfsrpc_pathconf(vp, &pc, &has_namedattr, td->td_ucred, - td, &nfsva, &attrflag); + error = nfsrpc_pathconf(vp, &pc, &has_namedattr, &clone_blksize, + td->td_ucred, td, &nfsva, &attrflag); if (attrflag != 0) (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error != 0) @@ -4771,6 +4847,9 @@ nfs_pathconf(struct vop_pathconf_args *ap) else *ap->a_retval = 0; break; + case _PC_CLONE_BLKSIZE: + *ap->a_retval = clone_blksize; + break; default: error = vop_stdpathconf(ap); diff --git a/sys/fs/nfsclient/nfsmount.h b/sys/fs/nfsclient/nfsmount.h index 37b84a015dab..ef876dd30e59 100644 --- a/sys/fs/nfsclient/nfsmount.h +++ b/sys/fs/nfsclient/nfsmount.h @@ -87,6 +87,7 @@ struct nfsmount { /* unclipped, wraps to 0 */ struct __rpc_client *nm_aconn[NFS_MAXNCONN - 1]; /* Additional nconn */ /* Locked via nm_sockreq.nr_mtx */ + uint32_t nm_cloneblksize; /* Block cloning alignment */ u_int16_t nm_krbnamelen; /* Krb5 host principal, if any */ u_int16_t nm_dirpathlen; /* and mount dirpath, for V4 */ u_int16_t nm_srvkrbnamelen; /* and the server's target name */ diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 8c427c66c156..b2966934f9b7 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -2113,7 +2113,8 @@ nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp, struct nfsvattr *nvap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp, struct ucred *cred, struct thread *p, int isdgram, int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno, - bool xattrsupp, bool has_hiddensystem, bool has_namedattr) + bool xattrsupp, bool has_hiddensystem, bool has_namedattr, + uint32_t clone_blksize) { struct statfs *sf; int error; @@ -2130,9 +2131,11 @@ nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp, sf = NULL; } } + error = nfsv4_fillattr(nd, mp, vp, NULL, &nvap->na_vattr, fhp, rderror, attrbitp, cred, p, isdgram, reterr, supports_nfsv4acls, at_root, - mounted_on_fileno, sf, xattrsupp, has_hiddensystem, has_namedattr); + mounted_on_fileno, sf, xattrsupp, has_hiddensystem, has_namedattr, + clone_blksize); free(sf, M_TEMP); NFSEXITCODE2(0, nd); return (error); @@ -2441,7 +2444,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, struct vnode *vp, struct nfsexstuff *exp) { struct dirent *dp; - u_int32_t *tl; + uint32_t clone_blksize, *tl; int dirlen; char *cpos, *cend, *rbuf; struct vnode *nvp; @@ -2943,6 +2946,7 @@ again: xattrsupp = false; has_hiddensystem = false; has_namedattr = false; + clone_blksize = 0; if (nvp != NULL) { supports_nfsv4acls = nfs_supportsnfsv4acls(nvp); @@ -2966,6 +2970,11 @@ again: &pathval) != 0) pathval = 0; has_namedattr = pathval > 0; + pathval = 0; + if (VOP_PATHCONF(nvp, _PC_CLONE_BLKSIZE, + &pathval) != 0) + pathval = 0; + clone_blksize = pathval; NFSVOPUNLOCK(nvp); } else supports_nfsv4acls = 0; @@ -2986,14 +2995,16 @@ again: nd->nd_cred, p, isdgram, 0, supports_nfsv4acls, at_root, mounted_on_fileno, xattrsupp, - has_hiddensystem, has_namedattr); + has_hiddensystem, has_namedattr, + clone_blksize); } else { dirlen += nfsvno_fillattr(nd, new_mp, nvp, nvap, &nfh, r, &attrbits, nd->nd_cred, p, isdgram, 0, supports_nfsv4acls, at_root, mounted_on_fileno, xattrsupp, - has_hiddensystem, has_namedattr); + has_hiddensystem, has_namedattr, + clone_blksize); } if (nvp != NULL) vrele(nvp); @@ -3740,6 +3751,7 @@ nfsrv_v4rootexport(void *argp, struct ucred *cred, struct thread *p) NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, nfsexargp->fspec); if ((error = namei(&nd)) != 0) goto out; + NDFREE_PNBUF(&nd); error = nfsvno_getfh(nd.ni_vp, &fh, p); vrele(nd.ni_vp); if (!error) { @@ -5690,7 +5702,8 @@ nfsrv_writedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, int len, if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR)) == (ND_NFSV4 | ND_V4WCCATTR)) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, - NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, + NULL); NFSD_DEBUG(4, "nfsrv_writedsdorpc: wcc attr=%d\n", error); if (error != 0) goto nfsmout; @@ -5721,7 +5734,8 @@ nfsrv_writedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, int len, if (error == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, - NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, + NULL); } NFSD_DEBUG(4, "nfsrv_writedsdorpc: aft loadattr=%d\n", error); nfsmout: @@ -5887,7 +5901,8 @@ nfsrv_allocatedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, - NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, + NULL); } else error = nd->nd_repstat; NFSD_DEBUG(4, "nfsrv_allocatedsdorpc: aft loadattr=%d\n", error); @@ -6054,7 +6069,8 @@ nfsrv_deallocatedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR)) == (ND_NFSV4 | ND_V4WCCATTR)) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, - NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, + NULL); NFSD_DEBUG(4, "nfsrv_deallocatedsdorpc: wcc attr=%d\n", error); if (error != 0) goto nfsmout; @@ -6068,7 +6084,8 @@ nfsrv_deallocatedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, - NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, + NULL); } else error = nd->nd_repstat; NFSD_DEBUG(4, "nfsrv_deallocatedsdorpc: aft loadattr=%d\n", error); @@ -6216,7 +6233,8 @@ nfsrv_setattrdsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p, if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR)) == (ND_NFSV4 | ND_V4WCCATTR)) { error = nfsv4_loadattr(nd, NULL, dsnap, NULL, NULL, 0, NULL, - NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, + NULL, NULL); NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: wcc attr=%d\n", error); if (error != 0) goto nfsmout; @@ -6241,7 +6259,7 @@ nfsrv_setattrdsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p, NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); error = nfsv4_loadattr(nd, NULL, dsnap, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, - NULL); + NULL, NULL); } NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: aft setattr loadattr=%d\n", error); nfsmout: @@ -6386,7 +6404,7 @@ nfsrv_setacldsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p, * the same type (VREG). */ nfsv4_fillattr(nd, NULL, vp, aclp, NULL, NULL, 0, &attrbits, NULL, - NULL, 0, 0, 0, 0, 0, NULL, false, false, false); + NULL, 0, 0, 0, 0, 0, NULL, false, false, false, 0); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) { @@ -6530,7 +6548,7 @@ nfsrv_getattrdsrpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p, if (nd->nd_repstat == 0) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); /* * We can only save the updated values in the extended * attribute if the vp is exclusively locked. diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index 9eebcda548c6..a881968b03be 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -253,6 +253,7 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, size_t atsiz; long pathval; bool has_hiddensystem, has_namedattr, xattrsupp; + uint32_t clone_blksize; if (nd->nd_repstat) goto out; @@ -330,6 +331,11 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, &pathval) != 0) pathval = 0; has_namedattr = pathval > 0; + pathval = 0; + if (VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE, + &pathval) != 0) + pathval = 0; + clone_blksize = pathval; mp = vp->v_mount; if (nfsrv_enable_crossmntpt != 0 && vp->v_type == VDIR && @@ -365,7 +371,7 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, isdgram, 1, supports_nfsv4acls, at_root, mounted_on_fileno, xattrsupp, has_hiddensystem, - has_namedattr); + has_namedattr, clone_blksize); vfs_unbusy(mp); } vrele(vp); @@ -4347,7 +4353,7 @@ nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, if (!nd->nd_repstat) { nfsvno_getfs(&fs, isdgram); error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, - sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, NULL, p, + sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, NULL, NULL, p, nd->nd_cred); if (!error) { if (nd->nd_procnum == NFSV4OP_NVERIFY) { @@ -6011,6 +6017,212 @@ nfsmout: } /* + * nfs clone service + */ +int +nfsrvd_clone(struct nfsrv_descript *nd, __unused int isdgram, + vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) +{ + uint32_t *tl; + struct nfsvattr at; + int error = 0, ret; + off_t inoff, outoff; + uint64_t len; + size_t xfer; + struct nfsstate inst, outst, *instp = &inst, *outstp = &outst; + struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo; + nfsquad_t clientid; + nfsv4stateid_t stateid; + nfsattrbit_t attrbits; + void *rl_rcookie, *rl_wcookie; + long pathval; + + rl_rcookie = rl_wcookie = NULL; + pathval = 0; + if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0 || + VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE, &pathval) != 0 || + pathval == 0) { + /* + * For a pNFS server, reply NFSERR_NOTSUPP so that the client + * will not do the clone and will do I/O on the DS(s). + * If vfs.nfsd.maxcopyrange set to 0, disable Clone. + */ + nd->nd_repstat = NFSERR_NOTSUPP; + goto nfsmout; + } + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER); + instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); + inlop->lo_flags = NFSLCK_READ; + instp->ls_ownerlen = 0; + instp->ls_op = NULL; + instp->ls_uid = nd->nd_cred->cr_uid; + instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); + clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; + clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; + if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) + clientid.qval = nd->nd_clientid.qval; + instp->ls_stateid.other[2] = *tl++; + outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); + outlop->lo_flags = NFSLCK_WRITE; + outstp->ls_ownerlen = 0; + outstp->ls_op = NULL; + outstp->ls_uid = nd->nd_cred->cr_uid; + outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); + outstp->ls_stateid.other[0] = *tl++; + outstp->ls_stateid.other[1] = *tl++; + outstp->ls_stateid.other[2] = *tl++; + inoff = fxdr_hyper(tl); tl += 2; + inlop->lo_first = inoff; + outoff = fxdr_hyper(tl); tl += 2; + outlop->lo_first = outoff; + len = fxdr_hyper(tl); + if (len == 0) { + /* len == 0 means to EOF. */ + inlop->lo_end = OFF_MAX; + outlop->lo_end = OFF_MAX; + } else { + inlop->lo_end = inlop->lo_first + len; + outlop->lo_end = outlop->lo_first + len; + } + + if ((inoff > OFF_MAX || outoff > OFF_MAX || + inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX || + inlop->lo_end < inlop->lo_first || outlop->lo_end < + outlop->lo_first)) + nd->nd_repstat = NFSERR_INVAL; + + if (nd->nd_repstat == 0 && vp->v_type != VREG) + nd->nd_repstat = NFSERR_WRONGTYPE; + + /* Check permissions for the input file. */ + NFSZERO_ATTRBIT(&attrbits); + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); + ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); + if (nd->nd_repstat == 0) + nd->nd_repstat = ret; + if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || + NFSVNO_EXSTRICTACCESS(exp))) + nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, + curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, + NULL); + if (nd->nd_repstat == 0) + nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL, + clientid, &stateid, exp, nd, curthread); + if (vp != tovp) { + NFSVOPUNLOCK(vp); + if (nd->nd_repstat != 0) + goto out; + + error = NFSVOPLOCK(tovp, LK_SHARED); + if (error != 0) + goto out; + pathval = 0; + if (VOP_PATHCONF(tovp, _PC_CLONE_BLKSIZE, &pathval) != 0 || + pathval == 0) + nd->nd_repstat = NFSERR_NOTSUPP; + else if (tovp->v_type != VREG) + nd->nd_repstat = NFSERR_WRONGTYPE; + } + + /* For the output file, we only need the Owner attribute. */ + ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits); + if (nd->nd_repstat == 0) + nd->nd_repstat = ret; + if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || + NFSVNO_EXSTRICTACCESS(exp))) + nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp, + curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, + NULL); + if (nd->nd_repstat == 0) + nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL, + clientid, &stateid, toexp, nd, curthread); + NFSVOPUNLOCK(tovp); + + /* Range lock the byte ranges for both invp and outvp. */ + if (nd->nd_repstat == 0) { + for (;;) { + if (len == 0) + rl_wcookie = vn_rangelock_wlock(tovp, outoff, + OFF_MAX); + else + rl_wcookie = vn_rangelock_wlock(tovp, outoff, + outoff + len); + if (vp != tovp) { + if (len == 0) + rl_rcookie = vn_rangelock_tryrlock(vp, + inoff, OFF_MAX); + else + rl_rcookie = vn_rangelock_tryrlock(vp, + inoff, inoff + len); + if (rl_rcookie != NULL) + break; + } else { + rl_rcookie = NULL; + break; + } + vn_rangelock_unlock(tovp, rl_wcookie); + if (len == 0) + rl_rcookie = vn_rangelock_rlock(vp, inoff, + OFF_MAX); + else + rl_rcookie = vn_rangelock_rlock(vp, inoff, + inoff + len); + vn_rangelock_unlock(vp, rl_rcookie); + } + + error = NFSVOPLOCK(vp, LK_SHARED); + if (error == 0) { + ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL); + if (ret == 0) { + /* + * Since invp is range locked, na_size should + * not change. + */ + if (len == 0 && at.na_size > inoff) + len = SSIZE_MAX; /* To EOF. */ + else if (inoff + len > at.na_size) + nd->nd_repstat = NFSERR_INVAL; + } + NFSVOPUNLOCK(vp); + if (ret != 0 && nd->nd_repstat == 0) + nd->nd_repstat = ret; + } else if (nd->nd_repstat == 0) + nd->nd_repstat = error; + } + + /* + * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange. + * This size limit can be set to limit the time a copy RPC will + * take. + */ + xfer = len; + if (nd->nd_repstat == 0) { + nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, + &xfer, COPY_FILE_RANGE_CLONE, nd->nd_cred, nd->nd_cred, + NULL); + if (nd->nd_repstat == ENOSYS) + nd->nd_repstat = NFSERR_INVAL; + } + + /* Unlock the ranges. */ + if (rl_rcookie != NULL) + vn_rangelock_unlock(vp, rl_rcookie); + if (rl_wcookie != NULL) + vn_rangelock_unlock(tovp, rl_wcookie); + +out: + vrele(vp); + vrele(tovp); + NFSEXITCODE2(error, nd); + return (error); +nfsmout: + vput(vp); + vrele(tovp); + NFSEXITCODE2(error, nd); + return (error); +} + +/* * nfs seek service */ int diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c index d6832b4f74be..636c4735a131 100644 --- a/sys/fs/nfsserver/nfs_nfsdsocket.c +++ b/sys/fs/nfsserver/nfs_nfsdsocket.c @@ -371,7 +371,7 @@ int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript *, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, - (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, + nfsrvd_clone, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index 2e27817389dd..111b0f26d0b5 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -4675,7 +4675,7 @@ errout: } else if (error == 0 && procnum == NFSV4OP_CBGETATTR) error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, - NULL, p, NULL); + NULL, NULL, p, NULL); m_freem(nd->nd_mrep); } NFSLOCKSTATE(); @@ -7731,6 +7731,7 @@ nfsrv_setdsserver(char *dspathp, char *mdspathp, NFSPROC_T *p, NFSD_DEBUG(4, "lookup=%d\n", error); if (error != 0) return (error); + NDFREE_PNBUF(&nd); if (nd.ni_vp->v_type != VDIR) { vput(nd.ni_vp); NFSD_DEBUG(4, "dspath not dir\n"); @@ -7767,6 +7768,7 @@ nfsrv_setdsserver(char *dspathp, char *mdspathp, NFSPROC_T *p, NFSD_DEBUG(4, "dsdirpath=%s lookup=%d\n", dsdirpath, error); if (error != 0) break; + NDFREE_PNBUF(&nd); if (nd.ni_vp->v_type != VDIR) { vput(nd.ni_vp); error = ENOTDIR; @@ -7795,6 +7797,7 @@ nfsrv_setdsserver(char *dspathp, char *mdspathp, NFSPROC_T *p, NFSD_DEBUG(4, "mds lookup=%d\n", error); if (error != 0) goto out; + NDFREE_PNBUF(&nd); if (nd.ni_vp->v_type != VDIR) { vput(nd.ni_vp); error = ENOTDIR; @@ -8654,6 +8657,7 @@ nfsrv_mdscopymr(char *mdspathp, char *dspathp, char *curdspathp, char *buf, NFSD_DEBUG(4, "lookup=%d\n", error); if (error != 0) return (error); + NDFREE_PNBUF(&nd); if (nd.ni_vp->v_type != VREG) { vput(nd.ni_vp); NFSD_DEBUG(4, "mdspath not reg\n"); @@ -8675,6 +8679,7 @@ nfsrv_mdscopymr(char *mdspathp, char *dspathp, char *curdspathp, char *buf, vput(vp); return (error); } + NDFREE_PNBUF(&nd); if (nd.ni_vp->v_type != VDIR) { vput(nd.ni_vp); vput(vp); @@ -8717,6 +8722,7 @@ nfsrv_mdscopymr(char *mdspathp, char *dspathp, char *curdspathp, char *buf, vput(curvp); return (error); } + NDFREE_PNBUF(&nd); if (nd.ni_vp->v_type != VDIR || nd.ni_vp == curvp) { vput(nd.ni_vp); vput(vp); diff --git a/sys/fs/p9fs/p9fs_vnops.c b/sys/fs/p9fs/p9fs_vnops.c index 227e2b93883e..acb73973d93b 100644 --- a/sys/fs/p9fs/p9fs_vnops.c +++ b/sys/fs/p9fs/p9fs_vnops.c @@ -1326,7 +1326,7 @@ p9fs_read(struct vop_read_args *ap) np = P9FS_VTON(vp); error = 0; - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); if (vp->v_type != VREG) return (EISDIR); diff --git a/sys/fs/tarfs/tarfs_vnops.c b/sys/fs/tarfs/tarfs_vnops.c index afb8e05f5929..acf18de5ab51 100644 --- a/sys/fs/tarfs/tarfs_vnops.c +++ b/sys/fs/tarfs/tarfs_vnops.c @@ -208,8 +208,7 @@ tarfs_getattr(struct vop_getattr_args *ap) vap->va_birthtime = tnp->birthtime; vap->va_gen = tnp->gen; vap->va_flags = tnp->flags; - vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ? - tnp->rdev : NODEV; + vap->va_rdev = VN_ISDEV(vp) ? tnp->rdev : NODEV; vap->va_bytes = round_page(tnp->physize); vap->va_filerev = 0; @@ -515,7 +514,7 @@ tarfs_read(struct vop_read_args *ap) uiop = ap->a_uio; vp = ap->a_vp; - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); if (vp->v_type != VREG) diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index 1237f6b92cdb..dd281d18d87d 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -551,7 +551,7 @@ tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *tmp, __enum_uint8(vtype) MPASS(IMPLIES(tmp->tm_root == NULL, parent == NULL && type == VDIR)); MPASS((type == VLNK) ^ (target == NULL)); - MPASS((type == VBLK || type == VCHR) ^ (rdev == VNOVAL)); + MPASS(VTYPE_ISDEV(type) ^ (rdev == VNOVAL)); if (tmp->tm_nodes_inuse >= tmp->tm_nodes_max) return (ENOSPC); diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 79b6c8b2e6a1..0f4ea2fdc28c 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -280,8 +280,7 @@ tmpfs_mknod(struct vop_mknod_args *v) struct componentname *cnp = v->a_cnp; struct vattr *vap = v->a_vap; - if (vap->va_type != VBLK && vap->va_type != VCHR && - vap->va_type != VFIFO) + if (!VATTR_ISDEV(vap) && vap->va_type != VFIFO) return (EINVAL); return (tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL)); @@ -462,8 +461,7 @@ tmpfs_stat(struct vop_stat_args *v) sb->st_nlink = node->tn_links; sb->st_uid = node->tn_uid; sb->st_gid = node->tn_gid; - sb->st_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ? - node->tn_rdev : NODEV; + sb->st_rdev = VN_ISDEV(vp) ? node->tn_rdev : NODEV; sb->st_size = node->tn_size; sb->st_atim.tv_sec = node->tn_atime.tv_sec; sb->st_atim.tv_nsec = node->tn_atime.tv_nsec; @@ -521,8 +519,7 @@ tmpfs_getattr(struct vop_getattr_args *v) vap->va_birthtime = node->tn_birthtime; vap->va_gen = node->tn_gen; vap->va_flags = node->tn_flags; - vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ? - node->tn_rdev : NODEV; + vap->va_rdev = VN_ISDEV(vp) ? node->tn_rdev : NODEV; if (vp->v_type == VREG) { #ifdef __ILP32__ vm_object_t obj = node->tn_reg.tn_aobj; @@ -1918,7 +1915,7 @@ tmpfs_deleteextattr(struct vop_deleteextattr_args *ap) node = VP_TO_TMPFS_NODE(vp); tmp = VFS_TO_TMPFS(vp->v_mount); - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred, ap->a_td, VWRITE); @@ -1956,7 +1953,7 @@ tmpfs_getextattr(struct vop_getextattr_args *ap) int error; node = VP_TO_TMPFS_NODE(vp); - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred, ap->a_td, VREAD); @@ -1993,7 +1990,7 @@ tmpfs_listextattr(struct vop_listextattr_args *ap) int error; node = VP_TO_TMPFS_NODE(vp); - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred, ap->a_td, VREAD); @@ -2037,7 +2034,7 @@ tmpfs_setextattr(struct vop_setextattr_args *ap) tmp = VFS_TO_TMPFS(vp->v_mount); attr_size = ap->a_uio->uio_resid; diff = 0; - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, ap->a_cred, ap->a_td, VWRITE); diff --git a/sys/geom/part/g_part.c b/sys/geom/part/g_part.c index 41125f6478ac..88e44b335b29 100644 --- a/sys/geom/part/g_part.c +++ b/sys/geom/part/g_part.c @@ -1046,7 +1046,7 @@ g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp) /* * Synthesize a disk geometry. Some partitioning schemes * depend on it and since some file systems need it even - * when the partitition scheme doesn't, we do it here in + * when the partition scheme doesn't, we do it here in * scheme-independent code. */ g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); @@ -1539,7 +1539,7 @@ g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp) /* * Synthesize a disk geometry. Some partitioning schemes * depend on it and since some file systems need it even - * when the partitition scheme doesn't, we do it here in + * when the partition scheme doesn't, we do it here in * scheme-independent code. */ pp = cp->provider; @@ -2023,7 +2023,7 @@ g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) /* * Synthesize a disk geometry. Some partitioning schemes * depend on it and since some file systems need it even - * when the partitition scheme doesn't, we do it here in + * when the partition scheme doesn't, we do it here in * scheme-independent code. */ g_part_geometry(table, cp, pp->mediasize / pp->sectorsize); diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index f577cd07ac7c..88b8967cd693 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -343,3 +343,4 @@ options HID_DEBUG # enable debug msgs device hid # Generic HID support device hidbus # Generic HID Bus options IICHID_SAMPLING # Workaround missing GPIO INTR support +options U2F_MAKE_UHID_ALIAS # install /dev/uhid alias for /dev/u2f/ diff --git a/sys/isa/isareg.h b/sys/isa/isareg.h index e89136c7e1e5..8b2d55608078 100644 --- a/sys/isa/isareg.h +++ b/sys/isa/isareg.h @@ -49,7 +49,7 @@ #define IO_RTC 0x070 /* RTC */ #define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */ -#define IO_MDA 0x3B0 /* Monochome Adapter */ +#define IO_MDA 0x3B0 /* Monochrome Adapter */ #define IO_VGA 0x3C0 /* E/VGA Ports */ #define IO_CGA 0x3D0 /* CGA Ports */ diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index c0a5479c9634..fcd232cde21e 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -145,8 +145,8 @@ struct sysent sysent[] = { { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 76 = obsolete vhangup */ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 77 = obsolete vlimit */ { .sy_narg = AS(mincore_args), .sy_call = (sy_call_t *)sys_mincore, .sy_auevent = AUE_MINCORE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 78 = mincore */ - { .sy_narg = AS(getgroups_args), .sy_call = (sy_call_t *)sys_getgroups, .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 79 = getgroups */ - { .sy_narg = AS(setgroups_args), .sy_call = (sy_call_t *)sys_setgroups, .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 80 = setgroups */ + { compat14(AS(freebsd14_getgroups_args),getgroups), .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 79 = freebsd14 getgroups */ + { compat14(AS(freebsd14_setgroups_args),setgroups), .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 80 = freebsd14 setgroups */ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getpgrp, .sy_auevent = AUE_GETPGRP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 81 = getpgrp */ { .sy_narg = AS(setpgid_args), .sy_call = (sy_call_t *)sys_setpgid, .sy_auevent = AUE_SETPGRP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 82 = setpgid */ { .sy_narg = AS(setitimer_args), .sy_call = (sy_call_t *)sys_setitimer, .sy_auevent = AUE_SETITIMER, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 83 = setitimer */ @@ -661,4 +661,6 @@ struct sysent sysent[] = { { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */ { .sy_narg = AS(inotify_add_watch_at_args), .sy_call = (sy_call_t *)sys_inotify_add_watch_at, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 593 = inotify_add_watch_at */ { .sy_narg = AS(inotify_rm_watch_args), .sy_call = (sy_call_t *)sys_inotify_rm_watch, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 594 = inotify_rm_watch */ + { .sy_narg = AS(getgroups_args), .sy_call = (sy_call_t *)sys_getgroups, .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 595 = getgroups */ + { .sy_narg = AS(setgroups_args), .sy_call = (sy_call_t *)sys_setgroups, .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 596 = setgroups */ }; diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 2cd5b7069023..0ca42d640767 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -310,6 +310,39 @@ sys_getegid(struct thread *td, struct getegid_args *uap) return (0); } +#ifdef COMPAT_FREEBSD14 +int +freebsd14_getgroups(struct thread *td, struct freebsd14_getgroups_args *uap) +{ + struct ucred *cred; + int ngrp, error; + + cred = td->td_ucred; + + /* + * For FreeBSD < 15.0, we account for the egid being placed at the + * beginning of the group list prior to all supplementary groups. + */ + ngrp = cred->cr_ngroups + 1; + if (uap->gidsetsize == 0) { + error = 0; + goto out; + } else if (uap->gidsetsize < ngrp) { + return (EINVAL); + } + + error = copyout(&cred->cr_gid, uap->gidset, sizeof(gid_t)); + if (error == 0) + error = copyout(cred->cr_groups, uap->gidset + 1, + (ngrp - 1) * sizeof(gid_t)); + +out: + td->td_retval[0] = ngrp; + return (error); + +} +#endif /* COMPAT_FREEBSD14 */ + #ifndef _SYS_SYSPROTO_H_ struct getgroups_args { int gidsetsize; @@ -320,18 +353,11 @@ int sys_getgroups(struct thread *td, struct getgroups_args *uap) { struct ucred *cred; - gid_t *ugidset; int ngrp, error; cred = td->td_ucred; - /* - * cr_gid has been moved out of cr_groups, but we'll continue exporting - * the egid as groups[0] for the time being until we audit userland for - * any surprises. - */ - ngrp = cred->cr_ngroups + 1; - + ngrp = cred->cr_ngroups; if (uap->gidsetsize == 0) { error = 0; goto out; @@ -339,14 +365,7 @@ sys_getgroups(struct thread *td, struct getgroups_args *uap) if (uap->gidsetsize < ngrp) return (EINVAL); - ugidset = uap->gidset; - error = copyout(&cred->cr_gid, ugidset, sizeof(*ugidset)); - if (error != 0) - goto out; - - if (ngrp > 1) - error = copyout(cred->cr_groups, ugidset + 1, - (ngrp - 1) * sizeof(*ugidset)); + error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t)); out: td->td_retval[0] = ngrp; return (error); @@ -1186,6 +1205,44 @@ fail: return (error); } +#ifdef COMPAT_FREEBSD14 +int +freebsd14_setgroups(struct thread *td, struct freebsd14_setgroups_args *uap) +{ + gid_t smallgroups[CRED_SMALLGROUPS_NB]; + gid_t *groups; + int gidsetsize, error; + + /* + * Before FreeBSD 15.0, we allow one more group to be supplied to + * account for the egid appearing before the supplementary groups. This + * may technically allow one more supplementary group for systems that + * did use the default NGROUPS_MAX if we round it back up to 1024. + */ + gidsetsize = uap->gidsetsize; + if (gidsetsize > ngroups_max + 1 || gidsetsize < 0) + return (EINVAL); + + if (gidsetsize > CRED_SMALLGROUPS_NB) + groups = malloc(gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK); + else + groups = smallgroups; + + error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t)); + if (error == 0) { + int ngroups = gidsetsize > 0 ? gidsetsize - 1 /* egid */ : 0; + + error = kern_setgroups(td, &ngroups, groups + 1); + if (error == 0 && gidsetsize > 0) + td->td_proc->p_ucred->cr_gid = groups[0]; + } + + if (groups != smallgroups) + free(groups, M_TEMP); + return (error); +} +#endif /* COMPAT_FREEBSD14 */ + #ifndef _SYS_SYSPROTO_H_ struct setgroups_args { int gidsetsize; @@ -1210,8 +1267,7 @@ sys_setgroups(struct thread *td, struct setgroups_args *uap) * setgroups() differ. */ gidsetsize = uap->gidsetsize; - /* XXXKE Limit to ngroups_max when we change the userland interface. */ - if (gidsetsize > ngroups_max + 1 || gidsetsize < 0) + if (gidsetsize > ngroups_max || gidsetsize < 0) return (EINVAL); if (gidsetsize > CRED_SMALLGROUPS_NB) @@ -1238,35 +1294,17 @@ kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups) struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; int ngrp, error; - gid_t egid; ngrp = *ngrpp; /* Sanity check size. */ - /* XXXKE Limit to ngroups_max when we change the userland interface. */ - if (ngrp < 0 || ngrp > ngroups_max + 1) + if (ngrp < 0 || ngrp > ngroups_max) return (EINVAL); AUDIT_ARG_GROUPSET(groups, ngrp); - /* - * setgroups(0, NULL) is a legitimate way of clearing the groups vector - * on non-BSD systems (which generally do not have the egid in the - * groups[0]). We risk security holes when running non-BSD software if - * we do not do the same. So we allow and treat 0 for 'ngrp' specially - * below (twice). - */ - if (ngrp != 0) { - /* - * To maintain userland compat for now, we use the first group - * as our egid and we'll use the rest as our supplemental - * groups. - */ - egid = groups[0]; - ngrp--; - groups++; - groups_normalize(&ngrp, groups); - *ngrpp = ngrp; - } + groups_normalize(&ngrp, groups); + *ngrpp = ngrp; + newcred = crget(); crextend(newcred, ngrp); PROC_LOCK(p); @@ -1289,15 +1327,7 @@ kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups) if (error) goto fail; - /* - * If some groups were passed, the first one is currently the desired - * egid. This code is to be removed (along with some commented block - * above) when setgroups() is changed to take only supplementary groups. - */ - if (ngrp != 0) - newcred->cr_gid = egid; crsetgroups_internal(newcred, ngrp, groups); - setsugid(p); proc_set_cred(p, newcred); PROC_UNLOCK(p); @@ -2891,7 +2921,8 @@ crextend(struct ucred *cr, int n) * Normalizes a set of groups to be applied to a 'struct ucred'. * * Normalization ensures that the supplementary groups are sorted in ascending - * order and do not contain duplicates. + * order and do not contain duplicates. This allows group_is_supplementary + * to do a binary search. */ static void groups_normalize(int *ngrp, gid_t *groups) diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 09bf4d519927..4122f9261871 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -84,8 +84,8 @@ const char *syscallnames[] = { "obs_vhangup", /* 76 = obsolete vhangup */ "obs_vlimit", /* 77 = obsolete vlimit */ "mincore", /* 78 = mincore */ - "getgroups", /* 79 = getgroups */ - "setgroups", /* 80 = setgroups */ + "compat14.getgroups", /* 79 = freebsd14 getgroups */ + "compat14.setgroups", /* 80 = freebsd14 setgroups */ "getpgrp", /* 81 = getpgrp */ "setpgid", /* 82 = setpgid */ "setitimer", /* 83 = setitimer */ @@ -600,4 +600,6 @@ const char *syscallnames[] = { "exterrctl", /* 592 = exterrctl */ "inotify_add_watch_at", /* 593 = inotify_add_watch_at */ "inotify_rm_watch", /* 594 = inotify_rm_watch */ + "getgroups", /* 595 = getgroups */ + "setgroups", /* 596 = setgroups */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 53b5d3cbbba9..fa64597d14a5 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -552,13 +552,13 @@ _Out_writes_bytes_(len/PAGE_SIZE) char *vec ); } -79 AUE_GETGROUPS STD|CAPENABLED { +79 AUE_GETGROUPS STD|CAPENABLED|COMPAT14 { int getgroups( int gidsetsize, _Out_writes_opt_(gidsetsize) gid_t *gidset ); } -80 AUE_SETGROUPS STD { +80 AUE_SETGROUPS STD|COMPAT14 { int setgroups( int gidsetsize, _In_reads_(gidsetsize) const gid_t *gidset @@ -3371,5 +3371,17 @@ int wd ); } +595 AUE_GETGROUPS STD|CAPENABLED { + int getgroups( + int gidsetsize, + _Out_writes_opt_(gidsetsize) gid_t *gidset + ); + } +596 AUE_SETGROUPS STD { + int setgroups( + int gidsetsize, + _In_reads_(gidsetsize) const gid_t *gidset + ); + } ; vim: syntax=off diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c index 4dfc63924da9..2b1ea9eed8d4 100644 --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -454,22 +454,6 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 3; break; } - /* getgroups */ - case 79: { - struct getgroups_args *p = params; - iarg[a++] = p->gidsetsize; /* int */ - uarg[a++] = (intptr_t)p->gidset; /* gid_t * */ - *n_args = 2; - break; - } - /* setgroups */ - case 80: { - struct setgroups_args *p = params; - iarg[a++] = p->gidsetsize; /* int */ - uarg[a++] = (intptr_t)p->gidset; /* const gid_t * */ - *n_args = 2; - break; - } /* getpgrp */ case 81: { *n_args = 0; @@ -3500,6 +3484,22 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 2; break; } + /* getgroups */ + case 595: { + struct getgroups_args *p = params; + iarg[a++] = p->gidsetsize; /* int */ + uarg[a++] = (intptr_t)p->gidset; /* gid_t * */ + *n_args = 2; + break; + } + /* setgroups */ + case 596: { + struct setgroups_args *p = params; + iarg[a++] = p->gidsetsize; /* int */ + uarg[a++] = (intptr_t)p->gidset; /* const gid_t * */ + *n_args = 2; + break; + } default: *n_args = 0; break; @@ -4199,32 +4199,6 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* getgroups */ - case 79: - switch (ndx) { - case 0: - p = "int"; - break; - case 1: - p = "userland gid_t *"; - break; - default: - break; - }; - break; - /* setgroups */ - case 80: - switch (ndx) { - case 0: - p = "int"; - break; - case 1: - p = "userland const gid_t *"; - break; - default: - break; - }; - break; /* getpgrp */ case 81: break; @@ -9367,6 +9341,32 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* getgroups */ + case 595: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland gid_t *"; + break; + default: + break; + }; + break; + /* setgroups */ + case 596: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland const gid_t *"; + break; + default: + break; + }; + break; default: break; }; @@ -9633,16 +9633,6 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* getgroups */ - case 79: - if (ndx == 0 || ndx == 1) - p = "int"; - break; - /* setgroups */ - case 80: - if (ndx == 0 || ndx == 1) - p = "int"; - break; /* getpgrp */ case 81: /* setpgid */ @@ -11365,6 +11355,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; + /* getgroups */ + case 595: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setgroups */ + case 596: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index fa655c43d155..19c39e42bafa 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -5170,7 +5170,7 @@ bufstrategy(struct bufobj *bo, struct buf *bp) vp = bp->b_vp; KASSERT(vp == bo->bo_private, ("Inconsistent vnode bufstrategy")); - KASSERT(vp->v_type != VCHR && vp->v_type != VBLK, + KASSERT(!VN_ISDEV(vp), ("Wrong vnode in bufstrategy(bp=%p, vp=%p)", bp, vp)); i = VOP_STRATEGY(vp, bp); KASSERT(i == 0, ("VOP_STRATEGY failed bp=%p vp=%p", bp, bp->b_vp)); diff --git a/sys/kern/vfs_inotify.c b/sys/kern/vfs_inotify.c index 746a5a39208e..b265a5ff3a62 100644 --- a/sys/kern/vfs_inotify.c +++ b/sys/kern/vfs_inotify.c @@ -801,6 +801,7 @@ vn_inotify_add_watch(struct vnode *vp, struct inotify_softc *sc, uint32_t mask, vn_lock(vp, LK_SHARED | LK_RETRY); if (error != 0) break; + NDFREE_PNBUF(&nd); vn_irflag_set_cond(nd.ni_vp, VIRF_INOTIFY_PARENT); vrele(nd.ni_vp); } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index b805e147bd62..bf3ed9d515dc 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -2839,7 +2839,7 @@ setfflags(struct thread *td, struct vnode *vp, u_long flags) * if they are allowed to set flags and programs assume that * chown can't fail when done as root. */ - if (vp->v_type == VCHR || vp->v_type == VBLK) { + if (VN_ISDEV(vp)) { error = priv_check(td, PRIV_VFS_CHFLAGS_DEV); if (error != 0) return (error); diff --git a/sys/libkern/qsort.c b/sys/libkern/qsort.c index 0255a3d64d76..342b1525dd8a 100644 --- a/sys/libkern/qsort.c +++ b/sys/libkern/qsort.c @@ -114,11 +114,10 @@ qsort(void *a, size_t n, size_t es, cmp_t *cmp) char *pa, *pb, *pc, *pd, *pl, *pm, *pn; size_t d1, d2; int cmp_result; - int swaptype_long, swaptype_int, swap_cnt; + int swaptype_long, swaptype_int; loop: SWAPINIT(long, a, es); SWAPINIT(int, a, es); - swap_cnt = 0; if (n < 7) { for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) for (pl = pm; @@ -147,7 +146,6 @@ loop: SWAPINIT(long, a, es); for (;;) { while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) { if (cmp_result == 0) { - swap_cnt = 1; swap(pa, pb); pa += es; } @@ -155,7 +153,6 @@ loop: SWAPINIT(long, a, es); } while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) { if (cmp_result == 0) { - swap_cnt = 1; swap(pc, pd); pd -= es; } @@ -164,18 +161,9 @@ loop: SWAPINIT(long, a, es); if (pb > pc) break; swap(pb, pc); - swap_cnt = 1; pb += es; pc -= es; } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) - for (pl = pm; - pl > (char *)a && CMP(thunk, pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } pn = (char *)a + n * es; d1 = MIN(pa - (char *)a, pb - pa); diff --git a/sys/modules/hid/Makefile b/sys/modules/hid/Makefile index 56c3267d8684..10720570deb7 100644 --- a/sys/modules/hid/Makefile +++ b/sys/modules/hid/Makefile @@ -17,6 +17,7 @@ SUBDIR += \ hsctrl \ ietp \ ps4dshock \ + u2f \ xb360gp .include <bsd.subdir.mk> diff --git a/sys/modules/hid/u2f/Makefile b/sys/modules/hid/u2f/Makefile new file mode 100644 index 000000000000..227e7154035b --- /dev/null +++ b/sys/modules/hid/u2f/Makefile @@ -0,0 +1,8 @@ +.PATH: ${SRCTOP}/sys/dev/hid + +KMOD= u2f +SRCS= u2f.c +SRCS+= opt_hid.h opt_usb.h +SRCS+= bus_if.h device_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ossl/Makefile b/sys/modules/ossl/Makefile index 7a92742d6b36..ac2c752e922e 100644 --- a/sys/modules/ossl/Makefile +++ b/sys/modules/ossl/Makefile @@ -29,6 +29,7 @@ SRCS.arm= \ SRCS.aarch64= \ chacha-armv8.S \ + chacha-armv8-sve.S \ poly1305-armv8.S \ sha1-armv8.S \ sha256-armv8.S \ diff --git a/sys/net/iflib.c b/sys/net/iflib.c index 6638c90882aa..2b43f6f19051 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -2910,7 +2910,9 @@ iflib_rxeof(iflib_rxq_t rxq, qidx_t budget) struct if_rxd_info ri; int err, budget_left, rx_bytes, rx_pkts; iflib_fl_t fl; +#if defined(INET6) || defined(INET) int lro_enabled; +#endif uint8_t retval = 0; /* @@ -2936,7 +2938,9 @@ iflib_rxeof(iflib_rxq_t rxq, qidx_t budget) return (retval); } +#if defined(INET6) || defined(INET) lro_enabled = (if_getcapenable(ifp) & IFCAP_LRO); +#endif /* pfil needs the vnet to be set */ CURVNET_SET_QUIET(if_getvnet(ifp)); diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index c095fc8f7765..ce63fcf9ffc0 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -101,7 +101,7 @@ sysctl_net_inet_tcp_nolocaltimewait(SYSCTL_HANDLER_ARGS) if (error == 0 && req->newptr) { V_nolocaltimewait = new; gone_in(16, "net.inet.tcp.nolocaltimewait is obsolete." - " Use net.inet.tcp.local_msl instead.\n"); + " Use net.inet.tcp.msl_local instead.\n"); } return (error); } diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 2f2f9abf1c83..3e6519118a40 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -448,7 +448,7 @@ udp_multi_input(struct mbuf *m, int proto, struct sockaddr_in *udp_in) /* * No matching pcb found; discard datagram. (No need * to send an ICMP Port Unreachable for a broadcast - * or multicast datgram.) + * or multicast datagram.) */ UDPSTAT_INC(udps_noport); if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 0027cf3bd230..1a32365f5d1d 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -341,7 +341,7 @@ udp6_multi_input(struct mbuf *m, int off, int proto, /* * No matching pcb found; discard datagram. (No need * to send an ICMP Port Unreachable for a broadcast - * or multicast datgram.) + * or multicast datagram.) */ UDPSTAT_INC(udps_noport); UDPSTAT_INC(udps_noportmcast); diff --git a/sys/powerpc/conf/GENERIC64 b/sys/powerpc/conf/GENERIC64 index 85711c8fc3ff..630c88b97dd7 100644 --- a/sys/powerpc/conf/GENERIC64 +++ b/sys/powerpc/conf/GENERIC64 @@ -293,3 +293,4 @@ device virtio_balloon # VirtIO Memory Balloon device options HID_DEBUG # enable debug msgs device hid # Generic HID support device hidbus # Generic HID Bus +options U2F_MAKE_UHID_ALIAS # install /dev/uhid alias for /dev/u2f/ diff --git a/sys/powerpc/conf/GENERIC64LE b/sys/powerpc/conf/GENERIC64LE index a56feb6574a4..eb9a9441425d 100644 --- a/sys/powerpc/conf/GENERIC64LE +++ b/sys/powerpc/conf/GENERIC64LE @@ -274,3 +274,4 @@ device virtio_balloon # VirtIO Memory Balloon device options HID_DEBUG # enable debug msgs device hid # Generic HID support device hidbus # Generic HID Bus +options U2F_MAKE_UHID_ALIAS # install /dev/uhid alias for /dev/u2f/ diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC index a8500fe80019..2ff711e80127 100644 --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -132,6 +132,7 @@ device umass # Disks/Mass storage - Requires scbus and da options HID_DEBUG # enable debug msgs device hid # Generic HID support device hidbus # Generic HID Bus +options U2F_MAKE_UHID_ALIAS # install /dev/uhid alias for /dev/u2f/ # Serial (COM) ports device uart # Generic UART driver diff --git a/sys/rpc/auth.h b/sys/rpc/auth.h index 3d58fb19536b..33c33ffd594d 100644 --- a/sys/rpc/auth.h +++ b/sys/rpc/auth.h @@ -246,6 +246,19 @@ extern AUTH *authunix_create_default(void); /* takes no parameters */ extern AUTH *authnone_create(void); /* takes no parameters */ extern AUTH *authtls_create(void); /* takes no parameters */ __END_DECLS +/* + * DES style authentication + * AUTH *authsecdes_create(servername, window, timehost, ckey) + * char *servername; - network name of server + * u_int window; - time to live + * const char *timehost; - optional hostname to sync with + * des_block *ckey; - optional conversation key to use + */ +__BEGIN_DECLS +extern AUTH *authdes_create (char *, u_int, struct sockaddr *, des_block *); +extern AUTH *authdes_seccreate (const char *, const u_int, const char *, + const des_block *); +__END_DECLS __BEGIN_DECLS extern bool_t xdr_opaque_auth (XDR *, struct opaque_auth *); @@ -267,6 +280,19 @@ extern void passwd2des ( char *, char * ); __END_DECLS /* + * + * These routines interface to the keyserv daemon + * + */ +__BEGIN_DECLS +extern int key_decryptsession(const char *, des_block *); +extern int key_encryptsession(const char *, des_block *); +extern int key_gendes(des_block *); +extern int key_setsecret(const char *); +extern int key_secretkey_is_set(void); +__END_DECLS + +/* * Publickey routines. */ __BEGIN_DECLS diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 1646aa108701..a830c9d4c622 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -159,6 +159,7 @@ typedef int dumper_hdr_t(struct dumperinfo *di, struct kerneldumpheader *kdh); #define GID_RT_PRIO 47 #define GID_ID_PRIO 48 #define GID_DIALER 68 +#define GID_U2F 116 #define GID_NOGROUP 65533 #define GID_NOBODY 65534 diff --git a/sys/sys/param.h b/sys/sys/param.h index c410a6ee666f..915bfe1abfcd 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -74,7 +74,7 @@ * cannot include sys/param.h and should only be updated here. */ #undef __FreeBSD_version -#define __FreeBSD_version 1500060 +#define __FreeBSD_version 1500062 /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index d703a11fda01..2d6903967e15 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -85,8 +85,8 @@ /* 76 is obsolete vhangup */ /* 77 is obsolete vlimit */ #define SYS_mincore 78 -#define SYS_getgroups 79 -#define SYS_setgroups 80 +#define SYS_freebsd14_getgroups 79 +#define SYS_freebsd14_setgroups 80 #define SYS_getpgrp 81 #define SYS_setpgid 82 #define SYS_setitimer 83 @@ -533,4 +533,6 @@ #define SYS_exterrctl 592 #define SYS_inotify_add_watch_at 593 #define SYS_inotify_rm_watch 594 -#define SYS_MAXSYSCALL 595 +#define SYS_getgroups 595 +#define SYS_setgroups 596 +#define SYS_MAXSYSCALL 597 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index b7ded62cacb4..d1172c2dc7bf 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -65,8 +65,8 @@ MIASM = \ mprotect.o \ madvise.o \ mincore.o \ - getgroups.o \ - setgroups.o \ + freebsd14_getgroups.o \ + freebsd14_setgroups.o \ getpgrp.o \ setpgid.o \ setitimer.o \ @@ -436,4 +436,6 @@ MIASM = \ setcred.o \ exterrctl.o \ inotify_add_watch_at.o \ - inotify_rm_watch.o + inotify_rm_watch.o \ + getgroups.o \ + setgroups.o diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index 8d666f9c8ee9..98311a6dbf94 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -273,14 +273,6 @@ struct mincore_args { char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; char vec_l_[PADL_(char *)]; char * vec; char vec_r_[PADR_(char *)]; }; -struct getgroups_args { - char gidsetsize_l_[PADL_(int)]; int gidsetsize; char gidsetsize_r_[PADR_(int)]; - char gidset_l_[PADL_(gid_t *)]; gid_t * gidset; char gidset_r_[PADR_(gid_t *)]; -}; -struct setgroups_args { - char gidsetsize_l_[PADL_(int)]; int gidsetsize; char gidsetsize_r_[PADR_(int)]; - char gidset_l_[PADL_(const gid_t *)]; const gid_t * gidset; char gidset_r_[PADR_(const gid_t *)]; -}; struct getpgrp_args { syscallarg_t dummy; }; @@ -1901,6 +1893,14 @@ struct inotify_rm_watch_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; char wd_l_[PADL_(int)]; int wd; char wd_r_[PADR_(int)]; }; +struct getgroups_args { + char gidsetsize_l_[PADL_(int)]; int gidsetsize; char gidsetsize_r_[PADR_(int)]; + char gidset_l_[PADL_(gid_t *)]; gid_t * gidset; char gidset_r_[PADR_(gid_t *)]; +}; +struct setgroups_args { + char gidsetsize_l_[PADL_(int)]; int gidsetsize; char gidsetsize_r_[PADR_(int)]; + char gidset_l_[PADL_(const gid_t *)]; const gid_t * gidset; char gidset_r_[PADR_(const gid_t *)]; +}; int sys__exit(struct thread *, struct _exit_args *); int sys_fork(struct thread *, struct fork_args *); int sys_read(struct thread *, struct read_args *); @@ -1957,8 +1957,6 @@ int sys_munmap(struct thread *, struct munmap_args *); int sys_mprotect(struct thread *, struct mprotect_args *); int sys_madvise(struct thread *, struct madvise_args *); int sys_mincore(struct thread *, struct mincore_args *); -int sys_getgroups(struct thread *, struct getgroups_args *); -int sys_setgroups(struct thread *, struct setgroups_args *); int sys_getpgrp(struct thread *, struct getpgrp_args *); int sys_setpgid(struct thread *, struct setpgid_args *); int sys_setitimer(struct thread *, struct setitimer_args *); @@ -2305,6 +2303,8 @@ int sys_setcred(struct thread *, struct setcred_args *); int sys_exterrctl(struct thread *, struct exterrctl_args *); int sys_inotify_add_watch_at(struct thread *, struct inotify_add_watch_at_args *); int sys_inotify_rm_watch(struct thread *, struct inotify_rm_watch_args *); +int sys_getgroups(struct thread *, struct getgroups_args *); +int sys_setgroups(struct thread *, struct setgroups_args *); #ifdef COMPAT_43 @@ -2799,6 +2799,16 @@ int freebsd13_swapoff(struct thread *, struct freebsd13_swapoff_args *); #ifdef COMPAT_FREEBSD14 +struct freebsd14_getgroups_args { + char gidsetsize_l_[PADL_(int)]; int gidsetsize; char gidsetsize_r_[PADR_(int)]; + char gidset_l_[PADL_(gid_t *)]; gid_t * gidset; char gidset_r_[PADR_(gid_t *)]; +}; +struct freebsd14_setgroups_args { + char gidsetsize_l_[PADL_(int)]; int gidsetsize; char gidsetsize_r_[PADR_(int)]; + char gidset_l_[PADL_(const gid_t *)]; const gid_t * gidset; char gidset_r_[PADR_(const gid_t *)]; +}; +int freebsd14_getgroups(struct thread *, struct freebsd14_getgroups_args *); +int freebsd14_setgroups(struct thread *, struct freebsd14_setgroups_args *); #endif /* COMPAT_FREEBSD14 */ @@ -2873,8 +2883,8 @@ int freebsd13_swapoff(struct thread *, struct freebsd13_swapoff_args *); #define SYS_AUE_mprotect AUE_MPROTECT #define SYS_AUE_madvise AUE_MADVISE #define SYS_AUE_mincore AUE_MINCORE -#define SYS_AUE_getgroups AUE_GETGROUPS -#define SYS_AUE_setgroups AUE_SETGROUPS +#define SYS_AUE_freebsd14_getgroups AUE_GETGROUPS +#define SYS_AUE_freebsd14_setgroups AUE_SETGROUPS #define SYS_AUE_getpgrp AUE_GETPGRP #define SYS_AUE_setpgid AUE_SETPGRP #define SYS_AUE_setitimer AUE_SETITIMER @@ -3289,6 +3299,8 @@ int freebsd13_swapoff(struct thread *, struct freebsd13_swapoff_args *); #define SYS_AUE_exterrctl AUE_NULL #define SYS_AUE_inotify_add_watch_at AUE_INOTIFY #define SYS_AUE_inotify_rm_watch AUE_INOTIFY +#define SYS_AUE_getgroups AUE_GETGROUPS +#define SYS_AUE_setgroups AUE_SETGROUPS #undef PAD_ #undef PADL_ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 074769d55c2d..6ef9bbec9446 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -67,6 +67,11 @@ __enum_uint8_decl(vtype) { VLASTTYPE = VMARKER, }; +/* + * We frequently need to test is something is a device node. + */ +#define VTYPE_ISDEV(vtype) ((vtype) == VCHR || (vtype) == VBLK) + __enum_uint8_decl(vstate) { VSTATE_UNINITIALIZED, VSTATE_CONSTRUCTED, @@ -199,6 +204,8 @@ struct vnode { int v_seqc_users; /* i modifications pending */ }; +#define VN_ISDEV(vp) VTYPE_ISDEV((vp)->v_type) + #ifndef DEBUG_LOCKS #ifdef _LP64 /* @@ -309,6 +316,8 @@ struct vattr { long va_spare; /* remain quad aligned */ }; +#define VATTR_ISDEV(vap) VTYPE_ISDEV((vap)->va_type) + /* * Flags for va_vaflags. */ diff --git a/sys/sys/watchdog.h b/sys/sys/watchdog.h index 4a16b18509f5..8401d343a6b7 100644 --- a/sys/sys/watchdog.h +++ b/sys/sys/watchdog.h @@ -32,15 +32,16 @@ #define _SYS_WATCHDOG_H #include <sys/ioccom.h> +#include <sys/_types.h> #define _PATH_WATCHDOG "fido" -#define WDIOCPATPAT _IOW('W', 42, u_int) /* pat the watchdog */ -#define WDIOC_SETTIMEOUT _IOW('W', 43, int) /* set/reset the timer */ -#define WDIOC_GETTIMEOUT _IOR('W', 44, int) /* get total timeout */ -#define WDIOC_GETTIMELEFT _IOR('W', 45, int) /* get time left */ -#define WDIOC_GETPRETIMEOUT _IOR('W', 46, int) /* get the pre-timeout */ -#define WDIOC_SETPRETIMEOUT _IOW('W', 47, int) /* set the pre-timeout */ +#define WDIOC_PATPAT _IOW('W', 52, sbintime_t) /* pat the watchdog */ +#define WDIOC_SETTIMEOUT _IOW('W', 53, sbintime_t) /* set/reset the timer */ +#define WDIOC_GETTIMEOUT _IOR('W', 54, sbintime_t) /* get total timeout */ +#define WDIOC_GETTIMELEFT _IOR('W', 55, sbintime_t) /* get time left */ +#define WDIOC_GETPRETIMEOUT _IOR('W', 56, sbintime_t) /* get the pre-timeout */ +#define WDIOC_SETPRETIMEOUT _IOW('W', 57, sbintime_t) /* set the pre-timeout */ /* set the action when a pre-timeout occurs see: WD_SOFT_* */ #define WDIOC_SETPRETIMEOUTACT _IOW('W', 48, int) @@ -48,6 +49,8 @@ #define WDIOC_SETSOFT _IOW('W', 49, int) #define WDIOC_SETSOFTTIMEOUTACT _IOW('W', 50, int) +#define WDIOC_CONTROL _IOW('W', 51, int) /* configure watchdog */ + #define WD_ACTIVE 0x8000000 /* * Watchdog reset, timeout set to value in WD_INTERVAL field. @@ -93,6 +96,11 @@ #define WD_TO_64SEC 36 #define WD_TO_128SEC 37 +/* Control options for WDIOC_CONTROL */ +#define WD_CTRL_DISABLE 0x00000000 +#define WD_CTRL_ENABLE 0x00000001 +#define WD_CTRL_RESET 0x00000002 + /* action on pre-timeout trigger */ #define WD_SOFT_PANIC 0x01 /* panic */ #define WD_SOFT_DDB 0x02 /* enter debugger */ @@ -105,11 +113,16 @@ #include <sys/_eventhandler.h> typedef void (*watchdog_fn)(void *, u_int, int *); +typedef void (*watchdog_sbt_fn)(void *, sbintime_t, sbintime_t *, int *); EVENTHANDLER_DECLARE(watchdog_list, watchdog_fn); +EVENTHANDLER_DECLARE(watchdog_sbt_list, watchdog_sbt_fn); u_int wdog_kern_last_timeout(void); int wdog_kern_pat(u_int utim); +sbintime_t wdog_kern_last_timeout_sbt(void); +int wdog_kern_pat_sbt(sbintime_t utim); +int wdog_control(int ctrl); /* * The following function pointer is used to attach a software watchdog diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 897a21032907..c7e2b3f4b8e6 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -1550,7 +1550,7 @@ ffs_openextattr( } */ *ap) { - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); return (ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td)); @@ -1572,7 +1572,7 @@ ffs_closeextattr( struct vnode *vp; vp = ap->a_vp; - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); if (ap->a_commit && (vp->v_mount->mnt_flag & MNT_RDONLY) != 0) return (EROFS); @@ -1610,7 +1610,7 @@ ffs_deleteextattr( vp = ap->a_vp; ip = VTOI(vp); - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); if (strlen(ap->a_name) == 0) return (EINVAL); @@ -1688,7 +1688,7 @@ ffs_getextattr( ip = VTOI(ap->a_vp); - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, @@ -1738,7 +1738,7 @@ ffs_listextattr( ip = VTOI(ap->a_vp); - if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, @@ -1803,7 +1803,7 @@ ffs_setextattr( ip = VTOI(vp); fs = ITOFS(ip); - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); if (strlen(ap->a_name) == 0) return (EINVAL); diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index ffc993aef9fc..0921eee92b9d 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -156,30 +156,30 @@ ufs_itimes_locked(struct vnode *vp) if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) return; - if ((vp->v_type == VBLK || vp->v_type == VCHR) && !DOINGSOFTDEP(vp)) + if (VN_ISDEV(vp) && !DOINGSOFTDEP(vp)) UFS_INODE_SET_FLAG(ip, IN_LAZYMOD); else if (((vp->v_mount->mnt_kern_flag & - (MNTK_SUSPENDED | MNTK_SUSPEND)) == 0) || - (ip->i_flag & (IN_CHANGE | IN_UPDATE))) + (MNTK_SUSPENDED | MNTK_SUSPEND)) == 0) || + (ip->i_flag & (IN_CHANGE | IN_UPDATE)) != 0) UFS_INODE_SET_FLAG(ip, IN_MODIFIED); - else if (ip->i_flag & IN_ACCESS) + else if ((ip->i_flag & IN_ACCESS) != 0) UFS_INODE_SET_FLAG(ip, IN_LAZYACCESS); vfs_timestamp(&ts); - if (ip->i_flag & IN_ACCESS) { + if ((ip->i_flag & IN_ACCESS) != 0) { DIP_SET(ip, i_atime, ts.tv_sec); DIP_SET(ip, i_atimensec, ts.tv_nsec); } - if (ip->i_flag & IN_UPDATE) { + if ((ip->i_flag & IN_UPDATE) != 0) { DIP_SET(ip, i_mtime, ts.tv_sec); DIP_SET(ip, i_mtimensec, ts.tv_nsec); } - if (ip->i_flag & IN_CHANGE) { + if ((ip->i_flag & IN_CHANGE) != 0) { DIP_SET(ip, i_ctime, ts.tv_sec); DIP_SET(ip, i_ctimensec, ts.tv_nsec); DIP_SET(ip, i_modrev, DIP(ip, i_modrev) + 1); } - out: +out: ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); } @@ -319,7 +319,7 @@ ufs_open(struct vop_open_args *ap) struct vnode *vp = ap->a_vp; struct inode *ip; - if (vp->v_type == VCHR || vp->v_type == VBLK) + if (VN_ISDEV(vp)) return (EOPNOTSUPP); ip = VTOI(vp); @@ -540,7 +540,7 @@ ufs_stat(struct vop_stat_args *ap) sb->st_uid = ip->i_uid; sb->st_gid = ip->i_gid; if (I_IS_UFS1(ip)) { - sb->st_rdev = ip->i_din1->di_rdev; + sb->st_rdev = VN_ISDEV(vp) ? ip->i_din1->di_rdev : NODEV; sb->st_size = ip->i_din1->di_size; sb->st_mtim.tv_sec = ip->i_din1->di_mtime; sb->st_mtim.tv_nsec = ip->i_din1->di_mtimensec; @@ -551,7 +551,7 @@ ufs_stat(struct vop_stat_args *ap) sb->st_blocks = dbtob((uint64_t)ip->i_din1->di_blocks) / S_BLKSIZE; sb->st_filerev = ip->i_din1->di_modrev; } else { - sb->st_rdev = ip->i_din2->di_rdev; + sb->st_rdev = VN_ISDEV(vp) ? ip->i_din2->di_rdev : NODEV; sb->st_size = ip->i_din2->di_size; sb->st_mtim.tv_sec = ip->i_din2->di_mtime; sb->st_mtim.tv_nsec = ip->i_din2->di_mtimensec; @@ -603,7 +603,7 @@ ufs_getattr( vap->va_uid = ip->i_uid; vap->va_gid = ip->i_gid; if (I_IS_UFS1(ip)) { - vap->va_rdev = ip->i_din1->di_rdev; + vap->va_rdev = VN_ISDEV(vp) ? ip->i_din1->di_rdev : NODEV; vap->va_size = ip->i_din1->di_size; vap->va_mtime.tv_sec = ip->i_din1->di_mtime; vap->va_mtime.tv_nsec = ip->i_din1->di_mtimensec; @@ -612,7 +612,7 @@ ufs_getattr( vap->va_bytes = dbtob((uint64_t)ip->i_din1->di_blocks); vap->va_filerev = ip->i_din1->di_modrev; } else { - vap->va_rdev = ip->i_din2->di_rdev; + vap->va_rdev = VN_ISDEV(vp) ? ip->i_din2->di_rdev : NODEV; vap->va_size = ip->i_din2->di_size; vap->va_mtime.tv_sec = ip->i_din2->di_mtime; vap->va_mtime.tv_nsec = ip->i_din2->di_mtimensec; diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index de8a6c52c08f..244aa31ea703 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -901,8 +901,7 @@ vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int count, int error, before, after, rbehind, rahead, poff, i; int bytecount, secmask; - KASSERT(vp->v_type != VCHR && vp->v_type != VBLK, - ("%s does not support devices", __func__)); + KASSERT(!VN_ISDEV(vp), ("%s does not support devices", __func__)); if (VN_IS_DOOMED(vp)) return (VM_PAGER_BAD); diff --git a/sys/x86/include/apicreg.h b/sys/x86/include/apicreg.h index d610d7f11a1c..1252647fbab3 100644 --- a/sys/x86/include/apicreg.h +++ b/sys/x86/include/apicreg.h @@ -296,6 +296,8 @@ typedef struct IOAPIC ioapic_t; /* constants relating to APIC ID registers */ #define APIC_ID_MASK 0xff000000 #define APIC_ID_SHIFT 24 +#define APIC_EXT_ID_MASK 0x00fe0000 +#define APIC_EXT_ID_SHIFT 17 #define APIC_ID_CLUSTER 0xf0 #define APIC_ID_CLUSTER_ID 0x0f #define APIC_MAX_CLUSTER 0xe |