diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index d3b1a0239e3f..785ab4913f8d 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -1,11527 +1,11530 @@ # # # This file lists old files (OLD_FILES), libraries (OLD_LIBS, MOVED_LIBS) # and directories (OLD_DIRS) which should get removed after an update. # Recently removed entries should be listed first (with the date as a # comment). OLD_LIBS and MOVED_LIBS should only list dynamic libraries. # Static libraries, links to dynamic libraries (lib*.so), and linker scripts # should be listed in OLD_FILES. OLD_LIBS and MOVED_LIBS are removed by the # delete-old-libs target, whereas OLD_FILES and OLD_DIRS are removed by the # delete-old target. This separation allows users to avoid deleting old # dynamic libraries still required by existing binaries. # # MOVED_LIBS should be used instead of OLD_LIBS when a library is moved # from usr/lib to lib or vice versa. This avoids removing libraries for # alternate ABIs (such as lib32) which store all libraries in a single # directory (e.g. usr/lib32). # # For files listed in OLD_FILES, OLD_LIBS, and MOVED_LIBS, the check-old* # and delete-old* targets will also delete associated debug symbols from # usr/lib/debug. # # In case of a complete directory hierarchy the sorting is in depth first # order. # # Files that are installed or removed depending on some build option # should be listed in /usr/src/tools/build/mk/OptionalObsoleteFiles.inc # instead of in this file. # # Before you commit changes to this file please check if any entries in # tools/build/mk/OptionalObsoleteFiles.inc can be removed. The following # command tells which files are listed more than once regardless of some # architecture specific conditionals, so you can not blindly trust the # output: # ( grep '+=' /usr/src/ObsoleteFiles.inc | sort -u ; \ # grep '+=' /usr/src/tools/build/mk/OptionalObsoleteFiles.inc | sort -u) | \ # sort | uniq -d # # To find regular duplicates not dependent on optional components, you can # also use something that will not give you false positives, e.g.: # for t in `make -V TARGETS universe`; do # __MAKE_CONF=/dev/null make -f Makefile.inc1 TARGET=$t \ # -V OLD_FILES -V OLD_LIBS -V MOVED_LIBS -V OLD_DIRS check-old | \ # xargs -n1 | sort | uniq -d; # done # # For optional components, you can use the following to see if some entries # in OptionalObsoleteFiles.inc have been obsoleted by ObsoleteFiles.inc # for o in tools/build/options/WITH*; do # __MAKE_CONF=/dev/null make -f Makefile.inc1 -D${o##*/} \ # -V OLD_FILES -V OLD_LIBS -V MOVED_LIBS -V OLD_DIRS check-old | \ # xargs -n1 | sort | uniq -d; # done +# 20250917: VREF macro removed +OLD_FILES+=usr/share/man/man9/VREF.9.gz + # 20250917: Remove a miscapitalized manual OLD_FILES+=usr/share/man/man9/vnet.9.gz OLD_FILES+=usr/share/man/man9/vimage.9.gz # 20250911: This tool is no longer needed OLD_FILES+=usr/tests/bin/cp/sparse # 20250826: Remove a misspelled manual OLD_FILES+=usr/share/man/man3/sysdecode_syscallnames.3.gz # 20250812: Remove a bogus manlink OLD_FILES+=usr/share/man/man3/quota_statfs.3.gz # 20250808: nvmfd removed from base install OLD_FILES+=usr/sbin/nvmfd OLD_FILES+=usr/share/man/man8/nvmfd.8.gz # 20250807: Replace lib/libgssapi with krb5/lib/gssapi OLD_FILES+=usr/include/gssapi_krb5/gssapi.h OLD_FILES+=usr/include/gssapi_krb5/gssapi/gssapi.h OLD_FILES+=usr/include/gssapi_krb5/gssapi/mechglue.h OLD_DIRS+=usr/include/gssapi_krb5/gssapi OLD_DIRS+=usr/include/gssapi_krb5 OLD_FILES+=etc/gssapi/qop # 20250802: libutil bumped to 10 OLD_LIBS+=lib/libutil.so.9 # 20250801: libopencsd libraries moved to /usr/lib and made private OLD_FILES+=lib/libopencsd.so.0 OLD_FILES+=usr/lib/libopencsd.a OLD_FILES+=usr/lib/libopencsd.so # 20250801: Move compile_et to /usr/sbin OLD_FILES+=usr/share/et/compile_et # 20250728: zfsboot (MBR) removed OLD_FILES+=boot/zfsboot OLD_FILES+=usr/share/man/man8/zfsboot.8.gz # 20250728: Machine versions of 'runq.h' do not exist anymore OLD_FILES+=usr/include/machine/runq.h # 20250727: libvmmapi bumped to 7 OLD_LIBS+=usr/lib/libvmmapi.so.6 # 20250726: MIT KRB5 DSO bump OLD_LIBS+=usr/lib/libcom_err.so.121 OLD_LIBS+=usr/lib/libgssapi_krb5.so.121 OLD_LIBS+=usr/lib/libgssrpc.so.121 OLD_LIBS+=usr/lib/libk5crypto.so.121 OLD_LIBS+=usr/lib/libkadm5clnt_mit.so.121 OLD_LIBS+=usr/lib/libkadm5srv_mit.so.121 OLD_LIBS+=usr/lib/libkdb5.so.121 OLD_LIBS+=usr/lib/libkrad.so.121 OLD_LIBS+=usr/lib/libkrb5.so.121 OLD_LIBS+=usr/lib/libkrb5profile.so.121 OLD_LIBS+=usr/lib/libkrb5support.so.121 OLD_LIBS+=usr/lib/libverto.so.121 # 20250726: xargs tests rewritten OLD_FILES+=usr/tests/usr.bin/xargs/legacy_test OLD_FILES+=usr/tests/usr.bin/xargs/regress.n2147483647.out OLD_FILES+=usr/tests/usr.bin/xargs/regress.sh # 20250726: This file is now installed in /etc/dma OLD_FILES+=usr/share/examples/dma/auth.conf # 20250725: libbsnmp bumped to version 7 OLD_LIBS+=usr/lib/libbsnmp.so.6 # 20250725: Files which were briefly installed by WITH_MITKRB5 in 15.0. OLD_FILES+=usr/include/kadm5/admin_internal.h OLD_FILES+=usr/include/kadm5/admin_xdr.h OLD_FILES+=usr/include/kadm5/kadm_rpc.h OLD_FILES+=usr/include/kadm5/server_internal.h OLD_FILES+=usr/include/internal.h OLD_FILES+=usr/include/t_daemon.h OLD_FILES+=usr/include/t_test.h OLD_FILES+=usr/include/dyn.h OLD_FILES+=usr/include/dynP.h OLD_FILES+=usr/include/gssrpcint.h OLD_FILES+=usr/include/import_err.h OLD_FILES+=usr/share/man/man3/db_btree.3.gz OLD_FILES+=usr/share/man/man3/db_hash.3.gz OLD_FILES+=usr/share/man/man3/db_lock.3.gz OLD_FILES+=usr/share/man/man3/db_log.3.gz OLD_FILES+=usr/share/man/man3/db_mpool.3.gz OLD_FILES+=usr/share/man/man3/db_open.3.gz OLD_FILES+=usr/share/man/man3/db_recno.3.gz OLD_FILES+=usr/share/man/man3/db_txn.3.gz OLD_FILES+=usr/share/man/man5/profile.5.gz OLD_FILES+=usr/share/man/man8/kamdin.local.8.gz # 20250716: Remove an old manual page, vn(4) was removed in FreeBSD 5.0 OLD_FILES+=usr/share/man/man4/vn.4.gz # 20250710: share: Delete bitrotted make_*_driver.sh scripts OLD_FILES+=usr/share/examples/drivers/README OLD_FILES+=usr/share/examples/drivers/make_device_driver.sh OLD_FILES+=usr/share/examples/drivers/make_pseudo_driver.sh OLD_DIRS+=usr/share/examples/drivers # 20250710: shar(1) removed OLD_FILES+=usr/bin/shar # 20250708: For 34 days 15.0-CURRENT installed libkadm5clnt symlink without .so OLD_FILES+=usr/lib/libkadm5clnt # 20250626: For 11 days 15.0-CURRENT installed libtpool to the wrong location MOVED_LIBS+=usr/lib/libtpool.so.2 # 20250626: replace yaml.lua with lyaml OLD_FILES+=usr/share/flua/yaml.lua # 20250615: don't install man page for absent function OLD_FILES+=usr/share/man/man9/vm_map_simplify_entry.9.gz # 20250615: OpenSSL 3.5.0 OLD_LIBS+=lib/libcrypto.so.30 OLD_FILES+=usr/include/openssl/asn1_mac.h OLD_LIBS+=usr/lib/libssl.so.30 OLD_FILES+=usr/share/man/man3/TS_VERIFY_CTX_set_certs.3 OLD_FILES+=usr/share/man/man7/crypto.7 OLD_FILES+=usr/share/man/man7/migration_guide.7 OLD_FILES+=usr/share/man/man7/ssl.7 # 20250521: don't install zoneinfo version OLD_FILES+=usr/share/zoneinfo/version # 20250516: NDFREE(9) -> NDFREE_PNBUF(9) OLD_FILES+=usr/share/man/man9/NDFREE.9.gz # 20250511: mailx test renamed OLD_FILES+=usr/tests/usr.bin/mail/mail_sigint_test # 20250505: Remove audio(8) files after rename to sndctl(8) OLD_FILES+=usr/sbin/audio OLD_FILES+=usr/share/man/man8/audio.8.gz # 20250409: removal of iwlwifi firmware files OLD_FILES+=usr/share/doc/legal/intel_iwlwifi_firmware.LICENCE # 20250331: removal of TCPPCAP OLD_FILES+=usr/include/netinet/tcp_pcap.h # 20250310: caroot bundle updated OLD_FILES+=usr/share/certs/trusted/Entrust_Root_Certification_Authority_-_G4.pem OLD_FILES+=usr/share/certs/trusted/SecureSign_RootCA11.pem OLD_FILES+=usr/share/certs/trusted/Security_Communication_RootCA3.pem OLD_FILES+=usr/share/certs/trusted/SwissSign_Silver_CA_-_G2.pem OLD_FILES+=usr/share/certs/untrusted/AddTrust_External_Root.pem OLD_FILES+=usr/share/certs/untrusted/AddTrust_Low-Value_Services_Root.pem OLD_FILES+=usr/share/certs/untrusted/Staat_der_Nederlanden_Root_CA_-_G2.pem OLD_FILES+=usr/share/certs/untrusted/Cybertrust_Global_Root.pem OLD_FILES+=usr/share/certs/untrusted/DST_Root_CA_X3.pem OLD_FILES+=usr/share/certs/untrusted/GlobalSign_Root_CA_-_R2.pem OLD_FILES+=usr/share/certs/untrusted/QuoVadis_Root_CA.pem OLD_FILES+=usr/share/certs/untrusted/Sonera_Class_2_Root_CA.pem OLD_FILES+=usr/share/certs/untrusted/GeoTrust_Global_CA.pem OLD_FILES+=usr/share/certs/untrusted/Staat_der_Nederlanden_EV_Root_CA.pem OLD_FILES+=usr/share/certs/untrusted/E-Tugra_Certification_Authority.pem OLD_FILES+=usr/share/certs/untrusted/Hongkong_Post_Root_CA_1.pem OLD_FILES+=usr/share/certs/untrusted/Security_Communication_Root_CA.pem OLD_FILES+=usr/share/certs/untrusted/Trustis_FPS_Root_CA.pem # 20250205: bus_generic_attach.9 removed after the function was deprecated OLD_FILES+=usr/share/man/man9/bus_generic_attach.9.gz # 20250204: sys/vm/stack test symbols moved to /usr/lib/debug OLD_FILES+=usr/tests/sys/vm/stack/.debug/libsoxstack.so.debug OLD_DIRS+=usr/tests/sys/vm/stack/.debug # 20250129: libdevinfo bumped to version 7 OLD_LIBS+=usr/lib/libdevinfo.so.6 # 20250123: Remove gvinum(8) OLD_FILES+=sbin/gvinum OLD_FILES+=usr/share/man/man8/gvinum.8.gz # 20250122: Remove publickey(5) stuff OLD_FILES+=usr/bin/chkey OLD_FILES+=usr/bin/keylogin OLD_FILES+=usr/bin/keylogout OLD_FILES+=usr/sbin/keyserv OLD_FILES+=usr/bin/newkey OLD_FILES+=usr/share/man/man1/chkey.1.gz OLD_FILES+=usr/share/man/man1/keylogin.1.gz OLD_FILES+=usr/share/man/man1/keylogout.1.gz OLD_FILES+=usr/share/man/man5/publickey.5.gz OLD_FILES+=usr/share/man/man8/keyserv.1.gz OLD_FILES+=etc/rc.d/keyserv # 20241206: Remove Altera DE4 drivers OLD_FILES+=usr/share/man/man4/altera_atse.4.gz OLD_FILES+=usr/share/man/man4/altera_avgen.4.gz OLD_FILES+=usr/share/man/man4/altera_jtag_uart.4.gz OLD_FILES+=usr/share/man/man4/altera_sdcard.4.gz OLD_FILES+=usr/share/man/man4/altera_sdcardc.4.gz OLD_FILES+=usr/share/man/man4/atse.4.gz # 20241124: library and tests of OpenBSD dc OLD_FILES+=usr/share/misc/bc.library OLD_FILES+=usr/tests/usr.bin/dc/Kyuafile OLD_FILES+=usr/tests/usr.bin/dc/bcode OLD_FILES+=usr/tests/usr.bin/dc/inout OLD_DIRS+=usr/tests/usr.bin/dc # 20241119: rewrite mv tests OLD_FILES+=usr/tests/bin/mv/legacy_test # 20241112: Retire MK_PROFILE support OLD_FILES+=usr/lib/lib80211_p.a OLD_FILES+=usr/lib/lib9p_p.a OLD_FILES+=usr/lib/libBlocksRuntime_p.a OLD_FILES+=usr/lib/libalias_dummy_p.a OLD_FILES+=usr/lib/libalias_ftp_p.a OLD_FILES+=usr/lib/libalias_irc_p.a OLD_FILES+=usr/lib/libalias_nbt_p.a OLD_FILES+=usr/lib/libalias_p.a OLD_FILES+=usr/lib/libalias_pptp_p.a OLD_FILES+=usr/lib/libalias_skinny_p.a OLD_FILES+=usr/lib/libalias_smedia_p.a OLD_FILES+=usr/lib/libarchive_p.a OLD_FILES+=usr/lib/libasn1_p.a OLD_FILES+=usr/lib/libavl_p.a OLD_FILES+=usr/lib/libbe_p.a OLD_FILES+=usr/lib/libbegemot_p.a OLD_FILES+=usr/lib/libblacklist_p.a OLD_FILES+=usr/lib/libbluetooth_p.a OLD_FILES+=usr/lib/libbsdxml_p.a OLD_FILES+=usr/lib/libbsm_p.a OLD_FILES+=usr/lib/libbsnmp_p.a OLD_FILES+=usr/lib/libbz2_p.a OLD_FILES+=usr/lib/libc++_p.a OLD_FILES+=usr/lib/libc_p.a OLD_FILES+=usr/lib/libcalendar_p.a OLD_FILES+=usr/lib/libcam_p.a OLD_FILES+=usr/lib/libcom_err_p.a OLD_FILES+=usr/lib/libcompat_p.a OLD_FILES+=usr/lib/libcompiler_rt_p.a OLD_FILES+=usr/lib/libcrypt_p.a OLD_FILES+=usr/lib/libcrypto_p.a OLD_FILES+=usr/lib/libctf_p.a OLD_FILES+=usr/lib/libcurses_p.a OLD_FILES+=usr/lib/libcursesw_p.a OLD_FILES+=usr/lib/libcuse_p.a OLD_FILES+=usr/lib/libcxxrt_p.a OLD_FILES+=usr/lib/libdevctl_p.a OLD_FILES+=usr/lib/libdevinfo_p.a OLD_FILES+=usr/lib/libdevstat_p.a OLD_FILES+=usr/lib/libdialog_p.a OLD_FILES+=usr/lib/libdl_p.a OLD_FILES+=usr/lib/libdpv_p.a OLD_FILES+=usr/lib/libdtrace_p.a OLD_FILES+=usr/lib/libdwarf_p.a OLD_FILES+=usr/lib/libedit_p.a OLD_FILES+=usr/lib/libefivar_p.a OLD_FILES+=usr/lib/libelf_p.a OLD_FILES+=usr/lib/libexecinfo_p.a OLD_FILES+=usr/lib/libfetch_p.a OLD_FILES+=usr/lib/libfigpar_p.a OLD_FILES+=usr/lib/libfl_p.a OLD_FILES+=usr/lib/libform_p.a OLD_FILES+=usr/lib/libformw_p.a OLD_FILES+=usr/lib/libgcc_eh_p.a OLD_FILES+=usr/lib/libgcc_p.a OLD_FILES+=usr/lib/libgeom_p.a OLD_FILES+=usr/lib/libgpio_p.a OLD_FILES+=usr/lib/libgssapi_krb5_p.a OLD_FILES+=usr/lib/libgssapi_ntlm_p.a OLD_FILES+=usr/lib/libgssapi_p.a OLD_FILES+=usr/lib/libgssapi_spnego_p.a OLD_FILES+=usr/lib/libhdb_p.a OLD_FILES+=usr/lib/libheimbase_p.a OLD_FILES+=usr/lib/libheimntlm_p.a OLD_FILES+=usr/lib/libheimsqlite_p.a OLD_FILES+=usr/lib/libhistory_p.a OLD_FILES+=usr/lib/libhx509_p.a OLD_FILES+=usr/lib/libicp_p.a OLD_FILES+=usr/lib/libicp_rescue_p.a OLD_FILES+=usr/lib/libipsec_p.a OLD_FILES+=usr/lib/libipt_p.a OLD_FILES+=usr/lib/libjail_p.a OLD_FILES+=usr/lib/libkadm5clnt_p.a OLD_FILES+=usr/lib/libkadm5srv_p.a OLD_FILES+=usr/lib/libkafs5_p.a OLD_FILES+=usr/lib/libkdc_p.a OLD_FILES+=usr/lib/libkiconv_p.a OLD_FILES+=usr/lib/libkrb5_p.a OLD_FILES+=usr/lib/libkvm_p.a OLD_FILES+=usr/lib/libl_p.a OLD_FILES+=usr/lib/libln_p.a OLD_FILES+=usr/lib/liblzma_p.a OLD_FILES+=usr/lib/libm_p.a OLD_FILES+=usr/lib/libmagic_p.a OLD_FILES+=usr/lib/libmd_p.a OLD_FILES+=usr/lib/libmemstat_p.a OLD_FILES+=usr/lib/libmenu_p.a OLD_FILES+=usr/lib/libmenuw_p.a OLD_FILES+=usr/lib/libmilter_p.a OLD_FILES+=usr/lib/libmp_p.a OLD_FILES+=usr/lib/libmt_p.a OLD_FILES+=usr/lib/libncurses_p.a OLD_FILES+=usr/lib/libncursesw_p.a OLD_FILES+=usr/lib/libnetgraph_p.a OLD_FILES+=usr/lib/libnetmap_p.a OLD_FILES+=usr/lib/libnss_tacplus_p.a OLD_FILES+=usr/lib/libnv_p.a OLD_FILES+=usr/lib/libnvpair_p.a OLD_FILES+=usr/lib/libopencsd_p.a OLD_FILES+=usr/lib/libpanel_p.a OLD_FILES+=usr/lib/libpanelw_p.a OLD_FILES+=usr/lib/libpathconv_p.a OLD_FILES+=usr/lib/libpcap_p.a OLD_FILES+=usr/lib/libpjdlog_p.a OLD_FILES+=usr/lib/libpmc_p.a OLD_FILES+=usr/lib/libprivateatf-c++_p.a OLD_FILES+=usr/lib/libprivateatf-c_p.a OLD_FILES+=usr/lib/libprivateauditd_p.a OLD_FILES+=usr/lib/libprivatebsdstat_p.a OLD_FILES+=usr/lib/libprivatecbor_p.a OLD_FILES+=usr/lib/libprivatedevdctl_p.a OLD_FILES+=usr/lib/libprivateevent1_p.a OLD_FILES+=usr/lib/libprivatefido2_p.a OLD_FILES+=usr/lib/libprivategmock_main_p.a OLD_FILES+=usr/lib/libprivategmock_p.a OLD_FILES+=usr/lib/libprivategtest_main_p.a OLD_FILES+=usr/lib/libprivategtest_p.a OLD_FILES+=usr/lib/libprivateheimipcc_p.a OLD_FILES+=usr/lib/libprivateheimipcs_p.a OLD_FILES+=usr/lib/libprivateldns_p.a OLD_FILES+=usr/lib/libprivatesqlite3_p.a OLD_FILES+=usr/lib/libprivatessh_p.a OLD_FILES+=usr/lib/libprivateucl_p.a OLD_FILES+=usr/lib/libprivateunbound_p.a OLD_FILES+=usr/lib/libprivatezstd_p.a OLD_FILES+=usr/lib/libproc_p.a OLD_FILES+=usr/lib/libprocstat_p.a OLD_FILES+=usr/lib/libpthread_p.a OLD_FILES+=usr/lib/libradius_p.a OLD_FILES+=usr/lib/libregex_p.a OLD_FILES+=usr/lib/libroken_p.a OLD_FILES+=usr/lib/librpcsvc_p.a OLD_FILES+=usr/lib/librss_p.a OLD_FILES+=usr/lib/librt_p.a OLD_FILES+=usr/lib/librtld_db_p.a OLD_FILES+=usr/lib/libsbuf_p.a OLD_FILES+=usr/lib/libsdp_p.a OLD_FILES+=usr/lib/libsmb_p.a OLD_FILES+=usr/lib/libspl_p.a OLD_FILES+=usr/lib/libssl_p.a OLD_FILES+=usr/lib/libstats_p.a OLD_FILES+=usr/lib/libstdbuf_p.a OLD_FILES+=usr/lib/libstdthreads_p.a OLD_FILES+=usr/lib/libsysdecode_p.a OLD_FILES+=usr/lib/libtacplus_p.a OLD_FILES+=usr/lib/libtermcap_p.a OLD_FILES+=usr/lib/libtermcapw_p.a OLD_FILES+=usr/lib/libtermlib_p.a OLD_FILES+=usr/lib/libtermlibw_p.a OLD_FILES+=usr/lib/libthr_p.a OLD_FILES+=usr/lib/libthread_db_p.a OLD_FILES+=usr/lib/libtinfo_p.a OLD_FILES+=usr/lib/libtinfow_p.a OLD_FILES+=usr/lib/libtpool_p.a OLD_FILES+=usr/lib/libufs_p.a OLD_FILES+=usr/lib/libugidfw_p.a OLD_FILES+=usr/lib/libulog_p.a OLD_FILES+=usr/lib/libumem_p.a OLD_FILES+=usr/lib/libusb_p.a OLD_FILES+=usr/lib/libusbhid_p.a OLD_FILES+=usr/lib/libutempter_p.a OLD_FILES+=usr/lib/libutil_p.a OLD_FILES+=usr/lib/libuutil_p.a OLD_FILES+=usr/lib/libvgl_p.a OLD_FILES+=usr/lib/libvmmapi_p.a OLD_FILES+=usr/lib/libwind_p.a OLD_FILES+=usr/lib/libwrap_p.a OLD_FILES+=usr/lib/libxo_p.a OLD_FILES+=usr/lib/liby_p.a OLD_FILES+=usr/lib/libypclnt_p.a OLD_FILES+=usr/lib/libz_p.a OLD_FILES+=usr/lib/libzfs_core_p.a OLD_FILES+=usr/lib/libzfs_p.a OLD_FILES+=usr/lib/libzfsbootenv_p.a OLD_FILES+=usr/lib/libzutil_p.a # 20241112: move p9fs from section 5 to section 4 OLD_FILES+=usr/share/man/man5/p9fs.5.gz # 20241104: remove the outdated c2x.7 symlink in favor of c23.7 OLD_FILES+=usr/share/man/man7/c2x.7.gz # 20241023: new clang import which bumps version from 18 to 19 OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_texture_intrinsics.h OLD_FILES+=usr/lib/clang/18/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/18/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/18/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/18/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/18/include/__clang_hip_stdlib.h OLD_FILES+=usr/lib/clang/18/include/__stdarg___gnuc_va_list.h OLD_FILES+=usr/lib/clang/18/include/__stdarg___va_copy.h OLD_FILES+=usr/lib/clang/18/include/__stdarg_va_arg.h OLD_FILES+=usr/lib/clang/18/include/__stdarg_va_copy.h OLD_FILES+=usr/lib/clang/18/include/__stdarg_va_list.h OLD_FILES+=usr/lib/clang/18/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/18/include/__stddef_null.h OLD_FILES+=usr/lib/clang/18/include/__stddef_nullptr_t.h OLD_FILES+=usr/lib/clang/18/include/__stddef_offsetof.h OLD_FILES+=usr/lib/clang/18/include/__stddef_ptrdiff_t.h OLD_FILES+=usr/lib/clang/18/include/__stddef_rsize_t.h OLD_FILES+=usr/lib/clang/18/include/__stddef_size_t.h OLD_FILES+=usr/lib/clang/18/include/__stddef_unreachable.h OLD_FILES+=usr/lib/clang/18/include/__stddef_wchar_t.h OLD_FILES+=usr/lib/clang/18/include/__stddef_wint_t.h OLD_FILES+=usr/lib/clang/18/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/18/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/18/include/adcintrin.h OLD_FILES+=usr/lib/clang/18/include/adxintrin.h OLD_FILES+=usr/lib/clang/18/include/altivec.h OLD_FILES+=usr/lib/clang/18/include/ammintrin.h OLD_FILES+=usr/lib/clang/18/include/amxcomplexintrin.h OLD_FILES+=usr/lib/clang/18/include/amxfp16intrin.h OLD_FILES+=usr/lib/clang/18/include/amxintrin.h OLD_FILES+=usr/lib/clang/18/include/arm64intr.h OLD_FILES+=usr/lib/clang/18/include/arm_acle.h OLD_FILES+=usr/lib/clang/18/include/arm_bf16.h OLD_FILES+=usr/lib/clang/18/include/arm_cde.h OLD_FILES+=usr/lib/clang/18/include/arm_cmse.h OLD_FILES+=usr/lib/clang/18/include/arm_fp16.h OLD_FILES+=usr/lib/clang/18/include/arm_mve.h OLD_FILES+=usr/lib/clang/18/include/arm_neon.h OLD_FILES+=usr/lib/clang/18/include/arm_neon_sve_bridge.h OLD_FILES+=usr/lib/clang/18/include/arm_sme_draft_spec_subject_to_change.h OLD_FILES+=usr/lib/clang/18/include/arm_sve.h OLD_FILES+=usr/lib/clang/18/include/arm_vector_types.h OLD_FILES+=usr/lib/clang/18/include/armintr.h OLD_FILES+=usr/lib/clang/18/include/avx2intrin.h OLD_FILES+=usr/lib/clang/18/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/18/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512fp16intrin.h OLD_FILES+=usr/lib/clang/18/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vlfp16intrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/18/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/18/include/avxifmaintrin.h OLD_FILES+=usr/lib/clang/18/include/avxintrin.h OLD_FILES+=usr/lib/clang/18/include/avxneconvertintrin.h OLD_FILES+=usr/lib/clang/18/include/avxvnniint16intrin.h OLD_FILES+=usr/lib/clang/18/include/avxvnniint8intrin.h OLD_FILES+=usr/lib/clang/18/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/18/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/18/include/bmiintrin.h OLD_FILES+=usr/lib/clang/18/include/builtins.h OLD_FILES+=usr/lib/clang/18/include/cet.h OLD_FILES+=usr/lib/clang/18/include/cetintrin.h OLD_FILES+=usr/lib/clang/18/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/18/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/18/include/clwbintrin.h OLD_FILES+=usr/lib/clang/18/include/clzerointrin.h OLD_FILES+=usr/lib/clang/18/include/cmpccxaddintrin.h OLD_FILES+=usr/lib/clang/18/include/cpuid.h OLD_FILES+=usr/lib/clang/18/include/crc32intrin.h OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/bits/basic_string.h OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/bits/basic_string.tcc OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/bits/shared_ptr_base.h OLD_DIRS+=usr/lib/clang/18/include/cuda_wrappers/bits OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/cmath OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/18/include/cuda_wrappers OLD_FILES+=usr/lib/clang/18/include/emmintrin.h OLD_FILES+=usr/lib/clang/18/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/18/include/f16cintrin.h OLD_FILES+=usr/lib/clang/18/include/float.h OLD_FILES+=usr/lib/clang/18/include/fma4intrin.h OLD_FILES+=usr/lib/clang/18/include/fmaintrin.h OLD_FILES+=usr/lib/clang/18/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/18/include/fuzzer OLD_FILES+=usr/lib/clang/18/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/18/include/gfniintrin.h OLD_FILES+=usr/lib/clang/18/include/hexagon_circ_brev_intrinsics.h OLD_FILES+=usr/lib/clang/18/include/hexagon_protos.h OLD_FILES+=usr/lib/clang/18/include/hexagon_types.h OLD_FILES+=usr/lib/clang/18/include/hlsl/hlsl_basic_types.h OLD_FILES+=usr/lib/clang/18/include/hlsl/hlsl_intrinsics.h OLD_DIRS+=usr/lib/clang/18/include/hlsl OLD_FILES+=usr/lib/clang/18/include/hlsl.h OLD_FILES+=usr/lib/clang/18/include/hresetintrin.h OLD_FILES+=usr/lib/clang/18/include/htmintrin.h OLD_FILES+=usr/lib/clang/18/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/18/include/hvx_hexagon_protos.h OLD_FILES+=usr/lib/clang/18/include/ia32intrin.h OLD_FILES+=usr/lib/clang/18/include/immintrin.h OLD_FILES+=usr/lib/clang/18/include/intrin.h OLD_FILES+=usr/lib/clang/18/include/inttypes.h OLD_FILES+=usr/lib/clang/18/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/18/include/iso646.h OLD_FILES+=usr/lib/clang/18/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/18/include/larchintrin.h OLD_FILES+=usr/lib/clang/18/include/lasxintrin.h OLD_FILES+=usr/lib/clang/18/include/limits.h OLD_FILES+=usr/lib/clang/18/include/lsxintrin.h OLD_FILES+=usr/lib/clang/18/include/lwpintrin.h OLD_FILES+=usr/lib/clang/18/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/18/include/mm3dnow.h OLD_FILES+=usr/lib/clang/18/include/mm_malloc.h OLD_FILES+=usr/lib/clang/18/include/mmintrin.h OLD_FILES+=usr/lib/clang/18/include/module.modulemap OLD_FILES+=usr/lib/clang/18/include/movdirintrin.h OLD_FILES+=usr/lib/clang/18/include/msa.h OLD_FILES+=usr/lib/clang/18/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/18/include/nmmintrin.h OLD_FILES+=usr/lib/clang/18/include/omp-tools.h OLD_FILES+=usr/lib/clang/18/include/omp.h OLD_FILES+=usr/lib/clang/18/include/ompt.h OLD_FILES+=usr/lib/clang/18/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/18/include/opencl-c.h OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/18/include/openmp_wrappers OLD_FILES+=usr/lib/clang/18/include/orc_rt/c_api.h OLD_DIRS+=usr/lib/clang/18/include/orc_rt OLD_FILES+=usr/lib/clang/18/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/18/include/pkuintrin.h OLD_FILES+=usr/lib/clang/18/include/pmmintrin.h OLD_FILES+=usr/lib/clang/18/include/popcntintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/bmi2intrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/bmiintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/immintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/nmmintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/x86gprintrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/x86intrin.h OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/18/include/ppc_wrappers OLD_FILES+=usr/lib/clang/18/include/prfchiintrin.h OLD_FILES+=usr/lib/clang/18/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/18/include/profile/InstrProfData.inc OLD_FILES+=usr/lib/clang/18/include/profile/MemProfData.inc OLD_DIRS+=usr/lib/clang/18/include/profile OLD_FILES+=usr/lib/clang/18/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/18/include/raointintrin.h OLD_FILES+=usr/lib/clang/18/include/rdpruintrin.h OLD_FILES+=usr/lib/clang/18/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/18/include/riscv_bitmanip.h OLD_FILES+=usr/lib/clang/18/include/riscv_crypto.h OLD_FILES+=usr/lib/clang/18/include/riscv_ntlh.h OLD_FILES+=usr/lib/clang/18/include/riscv_vector.h OLD_FILES+=usr/lib/clang/18/include/rtmintrin.h OLD_FILES+=usr/lib/clang/18/include/s390intrin.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/memprof_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/18/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/18/include/sanitizer OLD_FILES+=usr/lib/clang/18/include/serializeintrin.h OLD_FILES+=usr/lib/clang/18/include/sgxintrin.h OLD_FILES+=usr/lib/clang/18/include/sha512intrin.h OLD_FILES+=usr/lib/clang/18/include/shaintrin.h OLD_FILES+=usr/lib/clang/18/include/sifive_vector.h OLD_FILES+=usr/lib/clang/18/include/sm3intrin.h OLD_FILES+=usr/lib/clang/18/include/sm4intrin.h OLD_FILES+=usr/lib/clang/18/include/smmintrin.h OLD_FILES+=usr/lib/clang/18/include/stdalign.h OLD_FILES+=usr/lib/clang/18/include/stdarg.h OLD_FILES+=usr/lib/clang/18/include/stdatomic.h OLD_FILES+=usr/lib/clang/18/include/stdbool.h OLD_FILES+=usr/lib/clang/18/include/stdckdint.h OLD_FILES+=usr/lib/clang/18/include/stddef.h OLD_FILES+=usr/lib/clang/18/include/stdint.h OLD_FILES+=usr/lib/clang/18/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/18/include/tbmintrin.h OLD_FILES+=usr/lib/clang/18/include/tgmath.h OLD_FILES+=usr/lib/clang/18/include/tmmintrin.h OLD_FILES+=usr/lib/clang/18/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/18/include/uintrintrin.h OLD_FILES+=usr/lib/clang/18/include/unwind.h OLD_FILES+=usr/lib/clang/18/include/usermsrintrin.h OLD_FILES+=usr/lib/clang/18/include/vadefs.h OLD_FILES+=usr/lib/clang/18/include/vaesintrin.h OLD_FILES+=usr/lib/clang/18/include/varargs.h OLD_FILES+=usr/lib/clang/18/include/vecintrin.h OLD_FILES+=usr/lib/clang/18/include/velintrin.h OLD_FILES+=usr/lib/clang/18/include/velintrin_approx.h OLD_FILES+=usr/lib/clang/18/include/velintrin_gen.h OLD_FILES+=usr/lib/clang/18/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/18/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/18/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/18/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/18/include/wmmintrin.h OLD_FILES+=usr/lib/clang/18/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/18/include/x86intrin.h OLD_FILES+=usr/lib/clang/18/include/xmmintrin.h OLD_FILES+=usr/lib/clang/18/include/xopintrin.h OLD_FILES+=usr/lib/clang/18/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/18/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/18/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/18/include/xray OLD_FILES+=usr/lib/clang/18/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/18/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/18/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/18/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/18/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/18/include OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-powerpc64.so OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-powerpc64le.so OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-riscv64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-riscv64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-riscv64.so OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-riscv64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_interceptors-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-riscv64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-riscv64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-riscv64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-riscv64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-riscv64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-riscv64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-powerpc64le.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/18/lib/freebsd OLD_DIRS+=usr/lib/clang/18/lib OLD_FILES+=usr/lib/clang/18/share/asan_ignorelist.txt OLD_FILES+=usr/lib/clang/18/share/cfi_ignorelist.txt OLD_FILES+=usr/lib/clang/18/share/msan_ignorelist.txt OLD_DIRS+=usr/lib/clang/18/share OLD_DIRS+=usr/lib/clang/18 # 20241023: new libc++ import which bumps version from 18 to 19 OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_any_all_none_of.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backend.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backend.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/any_of.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/backend.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/fill.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/find_if.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/for_each.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/libdispatch.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/merge.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/serial.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/stable_sort.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/thread.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/transform.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/transform_reduce.h OLD_DIRS+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends OLD_DIRS+=usr/include/c++/v1/__algorithm/pstl_backends OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_copy.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_count.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_equal.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_fill.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_find.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_for_each.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_frontend_dispatch.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_generate.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_is_partitioned.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_merge.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_move.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_replace.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_rotate_copy.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_sort.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_stable_sort.h OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_transform.h OLD_FILES+=usr/include/c++/v1/__availability OLD_FILES+=usr/include/c++/v1/__format/format_fwd.h OLD_FILES+=usr/include/c++/v1/__fwd/get.h OLD_FILES+=usr/include/c++/v1/__fwd/hash.h OLD_FILES+=usr/include/c++/v1/__numeric/pstl_reduce.h OLD_FILES+=usr/include/c++/v1/__numeric/pstl_transform_reduce.h OLD_FILES+=usr/include/c++/v1/__threading_support OLD_FILES+=usr/include/c++/v1/__tuple/pair_like.h OLD_FILES+=usr/include/c++/v1/__type_traits/apply_cv.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_copy_assignable.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_copy_constructible.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_default_constructible.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_move_assignable.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_move_constructible.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_copy_assignable.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_copy_constructible.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_default_constructible.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_move_assignable.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_move_constructible.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_copy_assignable.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_copy_constructible.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_default_constructible.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_move_assignable.h OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_move_constructible.h OLD_FILES+=usr/include/c++/v1/__type_traits/operation_traits.h OLD_FILES+=usr/include/c++/v1/experimental/__memory # 20241014: move divapp to netpfil/common/ OLD_FILES+=usr/tests/sys/netpfil/pf/divapp # 20240930: libmd bumped to version 7 OLD_LIBS+=lib/libmd.so.6 # 20240827: retire fips.so OLD_LIBS+=usr/lib/ossl-modules/fips.so # 20240824: sound examples: midi.c moved out of oss/ OLD_FILES+=usr/share/examples/sound/oss/midi.c # 20240824: sound examples: Remove ossinit.h and rename basic.c to audio.c OLD_FILES+=usr/share/examples/sound/oss/ossinit.h OLD_FILES+=usr/share/examples/sound/oss/basic.c # 20240824: sound examples: Remove ossmidi.h OLD_FILES+=usr/share/examples/sound/oss/ossmidi.h # 20240729: rename quick_exit_test to libc_exit_test OLD_FILES+=usr/tests/lib/libc/stdlib/quick_exit_test # 20240729: retire ifaddr_byindex OLD_FILES+=usr/share/man/man9/ifaddr_byindex.9.gz # 20240729: remove MD5(9) OLD_FILES+=usr/share/man/man9/MD5.9.gz OLD_FILES+=usr/share/man/man9/MD5Init.9.gz OLD_FILES+=usr/share/man/man9/MD5Transform.9.gz # 20240726: deprecate contigfree(9) OLD_FILES+=usr/share/man/man9/contigfree.9.gz # 20240721: retire vm_page_alloc_freelist OLD_FILES+=usr/share/man/man9/vm_page_alloc_freelist.9.gz OLD_FILES+=usr/share/man/man9/vm_page_alloc_freelist_domain.9.gz # 20240716: retire mergemaster OLD_FILES+=usr/sbin/mergemaster OLD_FILES+=usr/share/man/man8/mergemaster.8.gz # 20240527: csh: Remove hardlink /.cshrc OLD_FILES+=.cshrc # 20240511: move file system driver manuals to section four OLD_FILES+=usr/share/man/man5/autofs.5.gz OLD_FILES+=usr/share/man/man5/cd9660.5.gz OLD_FILES+=usr/share/man/man5/devfs.5.gz OLD_FILES+=usr/share/man/man5/ext2fs.5.gz OLD_FILES+=usr/share/man/man5/ext4fs.5.gz OLD_FILES+=usr/share/man/man5/fdescfs.5.gz OLD_FILES+=usr/share/man/man5/fusefs.5.gz OLD_FILES+=usr/share/man/man5/lindebugfs.5.gz OLD_FILES+=usr/share/man/man5/linprocfs.5.gz OLD_FILES+=usr/share/man/man5/linsysfs.5.gz OLD_FILES+=usr/share/man/man5/mqueuefs.5.gz OLD_FILES+=usr/share/man/man5/msdosfs.5.gz OLD_FILES+=usr/share/man/man5/msdos.5.gz OLD_FILES+=usr/share/man/man5/nullfs.5.gz OLD_FILES+=usr/share/man/man5/procfs.5.gz OLD_FILES+=usr/share/man/man5/smbfs.5.gz OLD_FILES+=usr/share/man/man5/tarfs.5.gz OLD_FILES+=usr/share/man/man5/tmpfs.5.gz OLD_FILES+=usr/share/man/man5/unionfs.5.gz OLD_FILES+=usr/share/man/man7/ffs.7.gz # 20240508: Remove remnants of portsnap(8) OLD_DIRS+=var/db/portsnap # 20240507: remove gbde OLD_FILES+=boot/kernel/geom_bde.ko OLD_FILES+=etc/rc.d/gbde OLD_FILES+=rescue/gbde OLD_FILES+=sbin/gbde OLD_FILES+=usr/share/man/man4/gbde.4.gz OLD_FILES+=usr/share/man/man8/gbde.8.gz # 20240422: remove improperly installed libcxxrt.so.1 MOVED_LIBS+=usr/lib/libcxxrt.so.1 # 20240414: unix_socketpair_test renamed OLD_FILES+=usr/tests/sys/kern/unix_socketpair_test # 20240406: new clang import which bumps version from 17 to 18 OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/17/include/__clang_cuda_texture_intrinsics.h OLD_FILES+=usr/lib/clang/17/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/17/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/17/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/17/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/17/include/__clang_hip_stdlib.h OLD_FILES+=usr/lib/clang/17/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/17/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/17/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/17/include/adxintrin.h OLD_FILES+=usr/lib/clang/17/include/altivec.h OLD_FILES+=usr/lib/clang/17/include/ammintrin.h OLD_FILES+=usr/lib/clang/17/include/amxcomplexintrin.h OLD_FILES+=usr/lib/clang/17/include/amxfp16intrin.h OLD_FILES+=usr/lib/clang/17/include/amxintrin.h OLD_FILES+=usr/lib/clang/17/include/arm64intr.h OLD_FILES+=usr/lib/clang/17/include/arm_acle.h OLD_FILES+=usr/lib/clang/17/include/arm_bf16.h OLD_FILES+=usr/lib/clang/17/include/arm_cde.h OLD_FILES+=usr/lib/clang/17/include/arm_cmse.h OLD_FILES+=usr/lib/clang/17/include/arm_fp16.h OLD_FILES+=usr/lib/clang/17/include/arm_mve.h OLD_FILES+=usr/lib/clang/17/include/arm_neon.h OLD_FILES+=usr/lib/clang/17/include/arm_neon_sve_bridge.h OLD_FILES+=usr/lib/clang/17/include/arm_sme_draft_spec_subject_to_change.h OLD_FILES+=usr/lib/clang/17/include/arm_sve.h OLD_FILES+=usr/lib/clang/17/include/armintr.h OLD_FILES+=usr/lib/clang/17/include/avx2intrin.h OLD_FILES+=usr/lib/clang/17/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/17/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512fp16intrin.h OLD_FILES+=usr/lib/clang/17/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vlfp16intrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/17/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/17/include/avxifmaintrin.h OLD_FILES+=usr/lib/clang/17/include/avxintrin.h OLD_FILES+=usr/lib/clang/17/include/avxneconvertintrin.h OLD_FILES+=usr/lib/clang/17/include/avxvnniint16intrin.h OLD_FILES+=usr/lib/clang/17/include/avxvnniint8intrin.h OLD_FILES+=usr/lib/clang/17/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/17/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/17/include/bmiintrin.h OLD_FILES+=usr/lib/clang/17/include/builtins.h OLD_FILES+=usr/lib/clang/17/include/cet.h OLD_FILES+=usr/lib/clang/17/include/cetintrin.h OLD_FILES+=usr/lib/clang/17/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/17/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/17/include/clwbintrin.h OLD_FILES+=usr/lib/clang/17/include/clzerointrin.h OLD_FILES+=usr/lib/clang/17/include/cmpccxaddintrin.h OLD_FILES+=usr/lib/clang/17/include/cpuid.h OLD_FILES+=usr/lib/clang/17/include/crc32intrin.h OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/bits/basic_string.h OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/bits/basic_string.tcc OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/bits/shared_ptr_base.h OLD_DIRS+=usr/lib/clang/17/include/cuda_wrappers/bits OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/cmath OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/new OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/shared_ptr_base.h OLD_DIRS+=usr/lib/clang/17/include/cuda_wrappers OLD_FILES+=usr/lib/clang/17/include/emmintrin.h OLD_FILES+=usr/lib/clang/17/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/17/include/f16cintrin.h OLD_FILES+=usr/lib/clang/17/include/float.h OLD_FILES+=usr/lib/clang/17/include/fma4intrin.h OLD_FILES+=usr/lib/clang/17/include/fmaintrin.h OLD_FILES+=usr/lib/clang/17/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/17/include/fuzzer OLD_FILES+=usr/lib/clang/17/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/17/include/gfniintrin.h OLD_FILES+=usr/lib/clang/17/include/hexagon_circ_brev_intrinsics.h OLD_FILES+=usr/lib/clang/17/include/hexagon_protos.h OLD_FILES+=usr/lib/clang/17/include/hexagon_types.h OLD_FILES+=usr/lib/clang/17/include/hlsl/hlsl_basic_types.h OLD_FILES+=usr/lib/clang/17/include/hlsl/hlsl_intrinsics.h OLD_DIRS+=usr/lib/clang/17/include/hlsl OLD_FILES+=usr/lib/clang/17/include/hlsl.h OLD_FILES+=usr/lib/clang/17/include/hresetintrin.h OLD_FILES+=usr/lib/clang/17/include/htmintrin.h OLD_FILES+=usr/lib/clang/17/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/17/include/hvx_hexagon_protos.h OLD_FILES+=usr/lib/clang/17/include/ia32intrin.h OLD_FILES+=usr/lib/clang/17/include/immintrin.h OLD_FILES+=usr/lib/clang/17/include/intrin.h OLD_FILES+=usr/lib/clang/17/include/inttypes.h OLD_FILES+=usr/lib/clang/17/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/17/include/iso646.h OLD_FILES+=usr/lib/clang/17/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/17/include/larchintrin.h OLD_FILES+=usr/lib/clang/17/include/limits.h OLD_FILES+=usr/lib/clang/17/include/lwpintrin.h OLD_FILES+=usr/lib/clang/17/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/17/include/mm3dnow.h OLD_FILES+=usr/lib/clang/17/include/mm_malloc.h OLD_FILES+=usr/lib/clang/17/include/mmintrin.h OLD_FILES+=usr/lib/clang/17/include/module.modulemap OLD_FILES+=usr/lib/clang/17/include/movdirintrin.h OLD_FILES+=usr/lib/clang/17/include/msa.h OLD_FILES+=usr/lib/clang/17/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/17/include/nmmintrin.h OLD_FILES+=usr/lib/clang/17/include/omp-tools.h OLD_FILES+=usr/lib/clang/17/include/omp.h OLD_FILES+=usr/lib/clang/17/include/ompt.h OLD_FILES+=usr/lib/clang/17/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/17/include/opencl-c.h OLD_FILES+=usr/lib/clang/17/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/17/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/17/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/17/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/17/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/17/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/17/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/17/include/openmp_wrappers OLD_FILES+=usr/lib/clang/17/include/orc_rt/c_api.h OLD_DIRS+=usr/lib/clang/17/include/orc_rt OLD_FILES+=usr/lib/clang/17/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/17/include/pkuintrin.h OLD_FILES+=usr/lib/clang/17/include/pmmintrin.h OLD_FILES+=usr/lib/clang/17/include/popcntintrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/bmi2intrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/bmiintrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/immintrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/x86gprintrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/x86intrin.h OLD_FILES+=usr/lib/clang/17/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/17/include/ppc_wrappers OLD_FILES+=usr/lib/clang/17/include/prfchiintrin.h OLD_FILES+=usr/lib/clang/17/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/17/include/profile/InstrProfData.inc OLD_FILES+=usr/lib/clang/17/include/profile/MemProfData.inc OLD_DIRS+=usr/lib/clang/17/include/profile OLD_FILES+=usr/lib/clang/17/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/17/include/raointintrin.h OLD_FILES+=usr/lib/clang/17/include/rdpruintrin.h OLD_FILES+=usr/lib/clang/17/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/17/include/riscv_ntlh.h OLD_FILES+=usr/lib/clang/17/include/riscv_vector.h OLD_FILES+=usr/lib/clang/17/include/rtmintrin.h OLD_FILES+=usr/lib/clang/17/include/s390intrin.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/memprof_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/17/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/17/include/sanitizer OLD_FILES+=usr/lib/clang/17/include/serializeintrin.h OLD_FILES+=usr/lib/clang/17/include/sgxintrin.h OLD_FILES+=usr/lib/clang/17/include/sha512intrin.h OLD_FILES+=usr/lib/clang/17/include/shaintrin.h OLD_FILES+=usr/lib/clang/17/include/sifive_vector.h OLD_FILES+=usr/lib/clang/17/include/sm3intrin.h OLD_FILES+=usr/lib/clang/17/include/sm4intrin.h OLD_FILES+=usr/lib/clang/17/include/smmintrin.h OLD_FILES+=usr/lib/clang/17/include/stdalign.h OLD_FILES+=usr/lib/clang/17/include/stdarg.h OLD_FILES+=usr/lib/clang/17/include/stdatomic.h OLD_FILES+=usr/lib/clang/17/include/stdbool.h OLD_FILES+=usr/lib/clang/17/include/stddef.h OLD_FILES+=usr/lib/clang/17/include/stdint.h OLD_FILES+=usr/lib/clang/17/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/17/include/tbmintrin.h OLD_FILES+=usr/lib/clang/17/include/tgmath.h OLD_FILES+=usr/lib/clang/17/include/tmmintrin.h OLD_FILES+=usr/lib/clang/17/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/17/include/uintrintrin.h OLD_FILES+=usr/lib/clang/17/include/unwind.h OLD_FILES+=usr/lib/clang/17/include/vadefs.h OLD_FILES+=usr/lib/clang/17/include/vaesintrin.h OLD_FILES+=usr/lib/clang/17/include/varargs.h OLD_FILES+=usr/lib/clang/17/include/vecintrin.h OLD_FILES+=usr/lib/clang/17/include/velintrin.h OLD_FILES+=usr/lib/clang/17/include/velintrin_approx.h OLD_FILES+=usr/lib/clang/17/include/velintrin_gen.h OLD_FILES+=usr/lib/clang/17/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/17/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/17/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/17/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/17/include/wmmintrin.h OLD_FILES+=usr/lib/clang/17/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/17/include/x86intrin.h OLD_FILES+=usr/lib/clang/17/include/xmmintrin.h OLD_FILES+=usr/lib/clang/17/include/xopintrin.h OLD_FILES+=usr/lib/clang/17/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/17/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/17/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/17/include/xray OLD_FILES+=usr/lib/clang/17/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/17/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/17/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/17/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/17/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/17/include OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-powerpc64.so OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-powerpc64le.so OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-preinit-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-preinit-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-preinit-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-riscv64.so OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_cxx-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_static-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_static-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_static-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_static-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_static-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.asan_static-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.fuzzer_interceptors-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.msan-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.msan-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.msan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.msan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.profile-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats_client-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats_client-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats_client-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.tsan-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.tsan-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.tsan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.tsan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_minimal-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone_cxx-riscv64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-basic-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-fdr-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-profiling-powerpc64le.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/17/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/17/lib/freebsd OLD_DIRS+=usr/lib/clang/17/lib OLD_FILES+=usr/lib/clang/17/share/asan_ignorelist.txt OLD_FILES+=usr/lib/clang/17/share/cfi_ignorelist.txt OLD_FILES+=usr/lib/clang/17/share/msan_ignorelist.txt OLD_DIRS+=usr/lib/clang/17/share OLD_DIRS+=usr/lib/clang/17 # 20240406: new libc++ import which bumps version from 17 to 18 OLD_FILES+=usr/include/c++/v1/__pstl/internal/algorithm_fwd.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/algorithm_impl.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/execution_defs.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/execution_impl.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_algorithm_defs.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_algorithm_impl.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_memory_defs.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_memory_impl.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_numeric_defs.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_numeric_impl.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/memory_impl.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/numeric_fwd.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/numeric_impl.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_for.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_for_each.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_invoke.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_merge.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_scan.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_stable_partial_sort.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_stable_sort.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_transform_reduce.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_transform_scan.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/util.h OLD_DIRS+=usr/include/c++/v1/__pstl/internal/omp OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend_omp.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend_serial.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend_tbb.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend_utils.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/unseq_backend_simd.h OLD_FILES+=usr/include/c++/v1/__pstl/internal/utils.h OLD_DIRS+=usr/include/c++/v1/__pstl/internal OLD_FILES+=usr/include/c++/v1/__pstl_algorithm OLD_FILES+=usr/include/c++/v1/__pstl_memory OLD_FILES+=usr/include/c++/v1/__pstl_numeric OLD_FILES+=usr/include/c++/v1/__type_traits/predicate_traits.h OLD_FILES+=usr/include/c++/v1/__utility/terminate_on_exception.h OLD_FILES+=usr/include/c++/v1/experimental/deque OLD_FILES+=usr/include/c++/v1/experimental/forward_list OLD_FILES+=usr/include/c++/v1/experimental/list OLD_FILES+=usr/include/c++/v1/experimental/map OLD_FILES+=usr/include/c++/v1/experimental/memory_resource OLD_FILES+=usr/include/c++/v1/experimental/regex OLD_FILES+=usr/include/c++/v1/experimental/set OLD_FILES+=usr/include/c++/v1/experimental/string OLD_FILES+=usr/include/c++/v1/experimental/unordered_map OLD_FILES+=usr/include/c++/v1/experimental/unordered_set OLD_FILES+=usr/include/c++/v1/experimental/vector OLD_FILES+=usr/include/c++/v1/limits.h OLD_FILES+=usr/include/c++/v1/setjmp.h # 20240321: remove empty /usr/libdata/gcc directory OLD_DIRS+=usr/libdata/gcc # 20240315: stop installing CAM.4 link to scsi.4 OLD_FILES+=usr/share/man/man4/CAM.4.gz # 20240307: Improperly installed awk tests removed OLD_FILES+=usr/tests/usr.bin/awk/bugs-fixed/missing-precision.ok OLD_FILES+=usr/tests/usr.bin/awk/bugs-fixed/negative-nf.ok OLD_FILES+=usr/tests/usr.bin/awk/bugs-fixed/pfile-overflow.ok OLD_FILES+=usr/tests/usr.bin/awk/bugs-fixed/system-status.awk OLD_FILES+=usr/tests/usr.bin/awk/bugs-fixed/system-status.bad OLD_FILES+=usr/tests/usr.bin/awk/bugs-fixed/system-status.ok OLD_FILES+=usr/tests/usr.bin/awk/bugs-fixed/system-status.ok2 # 20240211: caroot bundle updated OLD_FILES+=usr/share/certs/trusted/Security_Communication_Root_CA.pem # 20240202: remove obsolete share/examples/IPv6/USAGE OLD_FILES+=usr/share/examples/IPv6/USAGE OLD_DIRS+=usr/share/examples/IPv6 # 20240122: callout_async_drain() removed OLD_FILES+=usr/share/man/man9/callout_async_drain.9.gz # 20240114: Removal of geom_map(4) OLD_FILES+=usr/share/man/man4/geom_map.4.gz # 20240112: remove pmap_init2() OLD_FILES+=usr/share/man/man9/pmap_init2.9.gz # 20240112: remove pmap_pinit2() OLD_FILES+=usr/share/man/man9/pmap_pinit2.9.gz # 20240112: replaced NetBSD tests for uniq with our own OLD_FILES+=usr/tests/usr.bin/uniq/d_basic.in OLD_FILES+=usr/tests/usr.bin/uniq/d_basic.out OLD_FILES+=usr/tests/usr.bin/uniq/d_counts.out OLD_FILES+=usr/tests/usr.bin/uniq/d_input.in OLD_FILES+=usr/tests/usr.bin/uniq/d_show_duplicates.out OLD_FILES+=usr/tests/usr.bin/uniq/d_show_uniques.out # 20231208: new clang import which bumps version from 16 to 17 OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_texture_intrinsics.h OLD_FILES+=usr/lib/clang/16/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/16/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/16/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/16/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/16/include/__clang_hip_stdlib.h OLD_FILES+=usr/lib/clang/16/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/16/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/16/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/16/include/adxintrin.h OLD_FILES+=usr/lib/clang/16/include/altivec.h OLD_FILES+=usr/lib/clang/16/include/ammintrin.h OLD_FILES+=usr/lib/clang/16/include/amxfp16intrin.h OLD_FILES+=usr/lib/clang/16/include/amxintrin.h OLD_FILES+=usr/lib/clang/16/include/arm64intr.h OLD_FILES+=usr/lib/clang/16/include/arm_acle.h OLD_FILES+=usr/lib/clang/16/include/arm_bf16.h OLD_FILES+=usr/lib/clang/16/include/arm_cde.h OLD_FILES+=usr/lib/clang/16/include/arm_cmse.h OLD_FILES+=usr/lib/clang/16/include/arm_fp16.h OLD_FILES+=usr/lib/clang/16/include/arm_mve.h OLD_FILES+=usr/lib/clang/16/include/arm_neon.h OLD_FILES+=usr/lib/clang/16/include/arm_neon_sve_bridge.h OLD_FILES+=usr/lib/clang/16/include/arm_sve.h OLD_FILES+=usr/lib/clang/16/include/armintr.h OLD_FILES+=usr/lib/clang/16/include/avx2intrin.h OLD_FILES+=usr/lib/clang/16/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/16/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512fp16intrin.h OLD_FILES+=usr/lib/clang/16/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vlfp16intrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/16/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/16/include/avxifmaintrin.h OLD_FILES+=usr/lib/clang/16/include/avxintrin.h OLD_FILES+=usr/lib/clang/16/include/avxneconvertintrin.h OLD_FILES+=usr/lib/clang/16/include/avxvnniint8intrin.h OLD_FILES+=usr/lib/clang/16/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/16/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/16/include/bmiintrin.h OLD_FILES+=usr/lib/clang/16/include/builtins.h OLD_FILES+=usr/lib/clang/16/include/cet.h OLD_FILES+=usr/lib/clang/16/include/cetintrin.h OLD_FILES+=usr/lib/clang/16/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/16/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/16/include/clwbintrin.h OLD_FILES+=usr/lib/clang/16/include/clzerointrin.h OLD_FILES+=usr/lib/clang/16/include/cmpccxaddintrin.h OLD_FILES+=usr/lib/clang/16/include/cpuid.h OLD_FILES+=usr/lib/clang/16/include/crc32intrin.h OLD_FILES+=usr/lib/clang/16/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/16/include/cuda_wrappers/cmath OLD_FILES+=usr/lib/clang/16/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/16/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/16/include/cuda_wrappers OLD_FILES+=usr/lib/clang/16/include/emmintrin.h OLD_FILES+=usr/lib/clang/16/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/16/include/f16cintrin.h OLD_FILES+=usr/lib/clang/16/include/float.h OLD_FILES+=usr/lib/clang/16/include/fma4intrin.h OLD_FILES+=usr/lib/clang/16/include/fmaintrin.h OLD_FILES+=usr/lib/clang/16/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/16/include/fuzzer OLD_FILES+=usr/lib/clang/16/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/16/include/gfniintrin.h OLD_FILES+=usr/lib/clang/16/include/hexagon_circ_brev_intrinsics.h OLD_FILES+=usr/lib/clang/16/include/hexagon_protos.h OLD_FILES+=usr/lib/clang/16/include/hexagon_types.h OLD_FILES+=usr/lib/clang/16/include/hlsl/hlsl_basic_types.h OLD_FILES+=usr/lib/clang/16/include/hlsl/hlsl_intrinsics.h OLD_DIRS+=usr/lib/clang/16/include/hlsl OLD_FILES+=usr/lib/clang/16/include/hlsl.h OLD_FILES+=usr/lib/clang/16/include/hresetintrin.h OLD_FILES+=usr/lib/clang/16/include/htmintrin.h OLD_FILES+=usr/lib/clang/16/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/16/include/hvx_hexagon_protos.h OLD_FILES+=usr/lib/clang/16/include/ia32intrin.h OLD_FILES+=usr/lib/clang/16/include/immintrin.h OLD_FILES+=usr/lib/clang/16/include/intrin.h OLD_FILES+=usr/lib/clang/16/include/inttypes.h OLD_FILES+=usr/lib/clang/16/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/16/include/iso646.h OLD_FILES+=usr/lib/clang/16/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/16/include/larchintrin.h OLD_FILES+=usr/lib/clang/16/include/limits.h OLD_FILES+=usr/lib/clang/16/include/lwpintrin.h OLD_FILES+=usr/lib/clang/16/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/16/include/mm3dnow.h OLD_FILES+=usr/lib/clang/16/include/mm_malloc.h OLD_FILES+=usr/lib/clang/16/include/mmintrin.h OLD_FILES+=usr/lib/clang/16/include/module.modulemap OLD_FILES+=usr/lib/clang/16/include/movdirintrin.h OLD_FILES+=usr/lib/clang/16/include/msa.h OLD_FILES+=usr/lib/clang/16/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/16/include/nmmintrin.h OLD_FILES+=usr/lib/clang/16/include/omp-tools.h OLD_FILES+=usr/lib/clang/16/include/omp.h OLD_FILES+=usr/lib/clang/16/include/ompt.h OLD_FILES+=usr/lib/clang/16/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/16/include/opencl-c.h OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/16/include/openmp_wrappers OLD_FILES+=usr/lib/clang/16/include/orc_rt/c_api.h OLD_DIRS+=usr/lib/clang/16/include/orc_rt OLD_FILES+=usr/lib/clang/16/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/16/include/pkuintrin.h OLD_FILES+=usr/lib/clang/16/include/pmmintrin.h OLD_FILES+=usr/lib/clang/16/include/popcntintrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/bmi2intrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/bmiintrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/immintrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/x86gprintrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/x86intrin.h OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/16/include/ppc_wrappers OLD_FILES+=usr/lib/clang/16/include/prfchiintrin.h OLD_FILES+=usr/lib/clang/16/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/16/include/profile/InstrProfData.inc OLD_FILES+=usr/lib/clang/16/include/profile/MemProfData.inc OLD_DIRS+=usr/lib/clang/16/include/profile OLD_FILES+=usr/lib/clang/16/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/16/include/raointintrin.h OLD_FILES+=usr/lib/clang/16/include/rdpruintrin.h OLD_FILES+=usr/lib/clang/16/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/16/include/riscv_vector.h OLD_FILES+=usr/lib/clang/16/include/rtmintrin.h OLD_FILES+=usr/lib/clang/16/include/s390intrin.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/memprof_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/16/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/16/include/sanitizer OLD_FILES+=usr/lib/clang/16/include/serializeintrin.h OLD_FILES+=usr/lib/clang/16/include/sgxintrin.h OLD_FILES+=usr/lib/clang/16/include/shaintrin.h OLD_FILES+=usr/lib/clang/16/include/smmintrin.h OLD_FILES+=usr/lib/clang/16/include/stdalign.h OLD_FILES+=usr/lib/clang/16/include/stdarg.h OLD_FILES+=usr/lib/clang/16/include/stdatomic.h OLD_FILES+=usr/lib/clang/16/include/stdbool.h OLD_FILES+=usr/lib/clang/16/include/stddef.h OLD_FILES+=usr/lib/clang/16/include/stdint.h OLD_FILES+=usr/lib/clang/16/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/16/include/tbmintrin.h OLD_FILES+=usr/lib/clang/16/include/tgmath.h OLD_FILES+=usr/lib/clang/16/include/tmmintrin.h OLD_FILES+=usr/lib/clang/16/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/16/include/uintrintrin.h OLD_FILES+=usr/lib/clang/16/include/unwind.h OLD_FILES+=usr/lib/clang/16/include/vadefs.h OLD_FILES+=usr/lib/clang/16/include/vaesintrin.h OLD_FILES+=usr/lib/clang/16/include/varargs.h OLD_FILES+=usr/lib/clang/16/include/vecintrin.h OLD_FILES+=usr/lib/clang/16/include/velintrin.h OLD_FILES+=usr/lib/clang/16/include/velintrin_approx.h OLD_FILES+=usr/lib/clang/16/include/velintrin_gen.h OLD_FILES+=usr/lib/clang/16/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/16/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/16/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/16/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/16/include/wmmintrin.h OLD_FILES+=usr/lib/clang/16/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/16/include/x86intrin.h OLD_FILES+=usr/lib/clang/16/include/xmmintrin.h OLD_FILES+=usr/lib/clang/16/include/xopintrin.h OLD_FILES+=usr/lib/clang/16/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/16/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/16/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/16/include/xray OLD_FILES+=usr/lib/clang/16/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/16/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/16/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/16/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/16/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/16/include OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-powerpc64.so OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-powerpc64le.so OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-riscv64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-riscv64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-riscv64.so OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-riscv64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_static-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_static-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_static-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_static-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-riscv64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-riscv64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-riscv64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-riscv64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-riscv64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-riscv64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-powerpc64le.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/16/lib/freebsd OLD_DIRS+=usr/lib/clang/16/lib OLD_FILES+=usr/lib/clang/16/share/asan_ignorelist.txt OLD_FILES+=usr/lib/clang/16/share/cfi_ignorelist.txt OLD_FILES+=usr/lib/clang/16/share/msan_ignorelist.txt OLD_DIRS+=usr/lib/clang/16/share OLD_DIRS+=usr/lib/clang/16 # 20231208: new libc++ import which bumps version from 16 to 17 OLD_FILES+=usr/include/c++/v1/__bsd_locale_defaults.h OLD_FILES+=usr/include/c++/v1/__bsd_locale_fallbacks.h OLD_FILES+=usr/include/c++/v1/__debug OLD_FILES+=usr/include/c++/v1/__errc OLD_FILES+=usr/include/c++/v1/__functional/unwrap_ref.h OLD_FILES+=usr/include/c++/v1/__mutex_base OLD_FILES+=usr/include/c++/v1/__ranges/copyable_box.h OLD_FILES+=usr/include/c++/v1/__std_stream OLD_FILES+=usr/include/c++/v1/__tuple_dir/apply_cv.h OLD_FILES+=usr/include/c++/v1/__tuple_dir/make_tuple_types.h OLD_FILES+=usr/include/c++/v1/__tuple_dir/pair_like.h OLD_FILES+=usr/include/c++/v1/__tuple_dir/sfinae_helpers.h OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_element.h OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_indices.h OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_like.h OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_like_ext.h OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_size.h OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_types.h OLD_DIRS+=usr/include/c++/v1/__tuple_dir OLD_FILES+=usr/include/c++/v1/experimental/algorithm OLD_FILES+=usr/include/c++/v1/experimental/coroutine OLD_FILES+=usr/include/c++/v1/experimental/functional # 20231117: libufs version bumped to 8 OLD_LIBS+=lib/libufs.so.7 # 20231018: pmc.k7(3) removed OLD_FILES+=usr/share/man/man3/pmc.k7.3.gz # 20231018: Remove misspelled man page link OLD_FILES+=usr/share/man/man3/dbm_dirnfo.3.gz # 20231006: rename tcp6_v4unmapped_bind_test OLD_FILES+=usr/tests/sys/netinet/tcp6_v4unmapped_bind_test # 20231005: Remove man page link for now gone net80211 function. OLD_FILES+=usr/share/man/man9/ieee80211_unref_node.9.gz # 20231005: bsdconfig remove support for floppy and ftp OLD_FILES+=usr/share/bsdconfig/media/floppy.subr OLD_FILES+=usr/share/bsdconfig/media/ftp.subr # 20230927: Man pages renamed to match the actual functions OLD_FILES+=usr/share/man/man9/cr_seeothergids.9.gz OLD_FILES+=usr/share/man/man9/cr_seeotheruids.9.gz # 20230925 OLD_FILES+=usr/share/examples/diskless/ME OLD_FILES+=usr/share/examples/diskless/README.BOOTP OLD_FILES+=usr/share/examples/diskless/README.TEMPLATING OLD_FILES+=usr/share/examples/diskless/clone_root # 20230905 OLD_FILES+=usr/share/doc/legal/realtek_rtw88_firmware.LICENCE # 20230828 MOVED_LIBS+=usr/lib/librt.so.1 # 20230826: OLD_FILES+=usr/share/man/man9/knlist_remove_inevent.9.gz # 20230825: caroot bundle updated OLD_FILES+=usr/share/certs/trusted/E-Tugra_Certification_Authority.pem OLD_FILES+=usr/share/certs/trusted/E-Tugra_Global_Root_CA_ECC_v3.pem OLD_FILES+=usr/share/certs/trusted/E-Tugra_Global_Root_CA_RSA_v3.pem OLD_FILES+=usr/share/certs/trusted/Hongkong_Post_Root_CA_1.pem # 20230807: GoogleTest 1.14.0 upgrade. OLD_FILES+=usr/include/private/gmock/gmock-generated-actions.h OLD_FILES+=usr/include/private/gmock/gmock-generated-function-mockers.h OLD_FILES+=usr/include/private/gmock/gmock-generated-matchers.h OLD_FILES+=usr/include/private/gmock/gmock-generated-nice-strict.h OLD_FILES+=usr/include/private/gmock/internal/gmock-generated-internal-utils.h OLD_FILES+=usr/include/private/gtest/internal/gtest-linked_ptr.h OLD_FILES+=usr/include/private/gtest/internal/gtest-param-util-generated.h OLD_FILES+=usr/include/private/gtest/internal/gtest-tuple.h OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-actions_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-function-mockers_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-internal-utils_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-matchers_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-matchers_test OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-linked-ptr-test # 20230807: Removal of the ath(4) AHB bus-frontend for MIPS OLD_FILES+=usr/share/man/man4/ath_ahb.4.gz OLD_FILES+=usr/share/man/man4/ath_pci.4.gz OLD_FILES+=usr/share/man/man4/if_ath_pci.4.gz # 20230803: Removal of support for cloning pseudo interfaces from iflib(9) OLD_FILES+=usr/include/net/iflib_private.h # 20230802: Remove a copy of libdtrace.so installed to the wrong path MOVED_LIBS+=usr/lib/libdtrace.so.2 # 20230726: Removal of support for the VTOC8 partitioning scheme OLD_FILES+=usr/include/sys/disk/vtoc.h OLD_FILES+=usr/include/sys/vtoc.h # 20230724: Remove unneeded arm headers .if ${TARGET_ARCH} == "arm" OLD_FILES+=usr/include/machine/atomic-v6.h OLD_FILES+=usr/include/machine/cpu-v6.h OLD_FILES+=usr/include/machine/pmap-v6.h OLD_FILES+=usr/include/machine/pte-v6.h OLD_FILES+=usr/include/machine/swi.h .endif # 20230714: gsignal OLD_FILES+=usr/share/man/man9/gsignal.9.gz # 20230704: kinst dtrace tests moved to common OLD_DIRS+=usr/tests/cddl/usr.sbin/dtrace/amd64/kinst # 20230626: Only install sys/dev/nvme/nvme.h to /usr/include OLD_FILES+=usr/include/dev/nvme/nvme_private.h # 20230623: OpenSSL 3.0.9 OLD_LIBS+=lib/libcrypto.so.111 OLD_FILES+=usr/include/openssl/rand_drbg.h OLD_LIBS+=usr/lib/engines/capi.so OLD_LIBS+=usr/lib/engines/padlock.so OLD_LIBS+=usr/lib/libssl.so.111 OLD_DIRS+=usr/lib/engines .for libcompat in ${_ALL_libcompats} OLD_DIRS+=usr/lib${libcompat}/engines .endfor OLD_FILES+=usr/share/man/man1/list.1 OLD_FILES+=usr/share/man/man1/openssl-tsget.1 OLD_FILES+=usr/share/man/man3/ECDH_get_ex_data.3 OLD_FILES+=usr/share/man/man3/ECDH_get_ex_new_index.3 OLD_FILES+=usr/share/man/man3/ECDH_set_ex_data.3 OLD_FILES+=usr/share/man/man3/ERR_GET_FUNC.3 OLD_FILES+=usr/share/man/man3/EVP_PKEY_CTX_hkdf_mode.3 OLD_FILES+=usr/share/man/man3/EVP_PKEY_set_alias_type.3 OLD_FILES+=usr/share/man/man3/EVP_aes.3 OLD_FILES+=usr/share/man/man3/EVP_aria.3 OLD_FILES+=usr/share/man/man3/EVP_camellia.3 OLD_FILES+=usr/share/man/man3/EVP_des.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_bytes.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_cleanup_entropy_fn.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_cleanup_nonce_fn.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_free.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_generate.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_get0_master.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_get0_private.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_get0_public.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_get_entropy_fn.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_get_ex_data.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_get_ex_new_index.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_get_nonce_fn.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_instantiate.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_new.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_reseed.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_secure_new.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_set.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_set_callbacks.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_set_defaults.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_set_ex_data.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_set_reseed_defaults.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_set_reseed_interval.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_set_reseed_time_interval.3 OLD_FILES+=usr/share/man/man3/RAND_DRBG_uninstantiate.3 OLD_FILES+=usr/share/man/man3/RSA_padding_add_SSLv23.3 OLD_FILES+=usr/share/man/man3/RSA_padding_check_SSLv23.3 OLD_FILES+=usr/share/man/man7/RAND_DRBG.7 OLD_FILES+=usr/share/man/man7/scrypt.7 # 20230622: new clang import which bumps version from 15.0.7 to 16.0.1 OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_cuda_texture_intrinsics.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/15.0.7/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/15.0.7/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/15.0.7/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/15.0.7/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/15.0.7/include/adxintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/altivec.h OLD_FILES+=usr/lib/clang/15.0.7/include/ammintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/amxintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm64intr.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm_acle.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm_bf16.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm_cde.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm_cmse.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm_fp16.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm_mve.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm_neon.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm_neon_sve_bridge.h OLD_FILES+=usr/lib/clang/15.0.7/include/arm_sve.h OLD_FILES+=usr/lib/clang/15.0.7/include/armintr.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx2intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512fp16intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vlfp16intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avxintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/bmiintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/builtins.h OLD_FILES+=usr/lib/clang/15.0.7/include/cet.h OLD_FILES+=usr/lib/clang/15.0.7/include/cetintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/clwbintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/clzerointrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/cpuid.h OLD_FILES+=usr/lib/clang/15.0.7/include/crc32intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/15.0.7/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/15.0.7/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/15.0.7/include/cuda_wrappers OLD_FILES+=usr/lib/clang/15.0.7/include/emmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/f16cintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/float.h OLD_FILES+=usr/lib/clang/15.0.7/include/fma4intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/fmaintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/15.0.7/include/fuzzer OLD_FILES+=usr/lib/clang/15.0.7/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/gfniintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/hexagon_circ_brev_intrinsics.h OLD_FILES+=usr/lib/clang/15.0.7/include/hexagon_protos.h OLD_FILES+=usr/lib/clang/15.0.7/include/hexagon_types.h OLD_FILES+=usr/lib/clang/15.0.7/include/hlsl/hlsl_basic_types.h OLD_FILES+=usr/lib/clang/15.0.7/include/hlsl/hlsl_intrinsics.h OLD_DIRS+=usr/lib/clang/15.0.7/include/hlsl OLD_FILES+=usr/lib/clang/15.0.7/include/hlsl.h OLD_FILES+=usr/lib/clang/15.0.7/include/hresetintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/htmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/hvx_hexagon_protos.h OLD_FILES+=usr/lib/clang/15.0.7/include/ia32intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/immintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/inttypes.h OLD_FILES+=usr/lib/clang/15.0.7/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/iso646.h OLD_FILES+=usr/lib/clang/15.0.7/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/limits.h OLD_FILES+=usr/lib/clang/15.0.7/include/lwpintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/mm3dnow.h OLD_FILES+=usr/lib/clang/15.0.7/include/mm_malloc.h OLD_FILES+=usr/lib/clang/15.0.7/include/mmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/module.modulemap OLD_FILES+=usr/lib/clang/15.0.7/include/movdirintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/msa.h OLD_FILES+=usr/lib/clang/15.0.7/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/nmmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/omp-tools.h OLD_FILES+=usr/lib/clang/15.0.7/include/omp.h OLD_FILES+=usr/lib/clang/15.0.7/include/ompt.h OLD_FILES+=usr/lib/clang/15.0.7/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/15.0.7/include/opencl-c.h OLD_FILES+=usr/lib/clang/15.0.7/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/15.0.7/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/15.0.7/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/15.0.7/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/15.0.7/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/15.0.7/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/15.0.7/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/15.0.7/include/openmp_wrappers OLD_FILES+=usr/lib/clang/15.0.7/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/pkuintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/pmmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/popcntintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/bmi2intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/bmiintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/immintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/x86gprintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/x86intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/15.0.7/include/ppc_wrappers OLD_FILES+=usr/lib/clang/15.0.7/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/profile/InstrProfData.inc OLD_FILES+=usr/lib/clang/15.0.7/include/profile/MemProfData.inc OLD_DIRS+=usr/lib/clang/15.0.7/include/profile OLD_FILES+=usr/lib/clang/15.0.7/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/rdpruintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/riscv_vector.h OLD_FILES+=usr/lib/clang/15.0.7/include/rtmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/s390intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/memprof_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/15.0.7/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/15.0.7/include/sanitizer OLD_FILES+=usr/lib/clang/15.0.7/include/serializeintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/sgxintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/shaintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/smmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/stdalign.h OLD_FILES+=usr/lib/clang/15.0.7/include/stdarg.h OLD_FILES+=usr/lib/clang/15.0.7/include/stdatomic.h OLD_FILES+=usr/lib/clang/15.0.7/include/stdbool.h OLD_FILES+=usr/lib/clang/15.0.7/include/stddef.h OLD_FILES+=usr/lib/clang/15.0.7/include/stdint.h OLD_FILES+=usr/lib/clang/15.0.7/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/15.0.7/include/tbmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/tgmath.h OLD_FILES+=usr/lib/clang/15.0.7/include/tmmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/uintrintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/unwind.h OLD_FILES+=usr/lib/clang/15.0.7/include/vadefs.h OLD_FILES+=usr/lib/clang/15.0.7/include/vaesintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/varargs.h OLD_FILES+=usr/lib/clang/15.0.7/include/vecintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/velintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/velintrin_approx.h OLD_FILES+=usr/lib/clang/15.0.7/include/velintrin_gen.h OLD_FILES+=usr/lib/clang/15.0.7/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/15.0.7/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/wmmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/x86intrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/xmmintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/xopintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/15.0.7/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/15.0.7/include/xray OLD_FILES+=usr/lib/clang/15.0.7/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/15.0.7/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/15.0.7/include OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-powerpc64.so OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-powerpc64le.so OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-preinit-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-preinit-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-preinit-riscv64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-riscv64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-riscv64.so OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_cxx-riscv64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_static-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_static-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_static-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.asan_static-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.msan-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.msan-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.msan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.msan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.profile-riscv64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats-riscv64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats_client-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats_client-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats_client-riscv64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.tsan-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.tsan-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.tsan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.tsan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_minimal-riscv64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone-riscv64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone_cxx-riscv64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-basic-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-fdr-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-profiling-powerpc64le.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/15.0.7/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/15.0.7/lib/freebsd OLD_DIRS+=usr/lib/clang/15.0.7/lib OLD_FILES+=usr/lib/clang/15.0.7/share/asan_ignorelist.txt OLD_FILES+=usr/lib/clang/15.0.7/share/cfi_ignorelist.txt OLD_FILES+=usr/lib/clang/15.0.7/share/msan_ignorelist.txt OLD_DIRS+=usr/lib/clang/15.0.7/share OLD_DIRS+=usr/lib/clang/15.0.7 # 20230622: new libc++ import which bumps version from 15.0.7 to 16.0.1 OLD_FILES+=usr/include/c++/v1/__bits OLD_FILES+=usr/include/c++/v1/__tuple OLD_FILES+=usr/include/c++/v1/__utility/transaction.h # 20230614: caroot bundle updated OLD_FILES+=usr/share/certs/trusted/Cybertrust_Global_Root.pem OLD_FILES+=usr/share/certs/trusted/DST_Root_CA_X3.pem OLD_FILES+=usr/share/certs/trusted/GlobalSign_Root_CA_-_R2.pem OLD_FILES+=usr/share/certs/trusted/Hellenic_Academic_and_Research_Institutions_RootCA_2011.pem OLD_FILES+=usr/share/certs/trusted/Network_Solutions_Certificate_Authority.pem OLD_FILES+=usr/share/certs/trusted/Staat_der_Nederlanden_EV_Root_CA.pem OLD_FILES+=usr/share/certs/trusted/TrustCor_ECA-1.pem OLD_FILES+=usr/share/certs/trusted/TrustCor_RootCert_CA-1.pem OLD_FILES+=usr/share/certs/trusted/TrustCor_RootCert_CA-2.pem # 20230510: twe(4) driver removed OLD_FILES+=usr/share/man/man4/twe.4.gz # 20230505: md5 tests are now self-contained OLD_FILES+=usr/tests/sbin/md5/1.inp OLD_FILES+=usr/tests/sbin/md5/1.sha512-p.chk OLD_FILES+=usr/tests/sbin/md5/1.sha512sum-p.chk OLD_FILES+=usr/tests/sbin/md5/2.inp OLD_FILES+=usr/tests/sbin/md5/2.sha512-p.chk OLD_FILES+=usr/tests/sbin/md5/2.sha512sum-p.chk OLD_FILES+=usr/tests/sbin/md5/3.inp OLD_FILES+=usr/tests/sbin/md5/3.sha512-p.chk OLD_FILES+=usr/tests/sbin/md5/3.sha512sum-p.chk OLD_FILES+=usr/tests/sbin/md5/4.inp OLD_FILES+=usr/tests/sbin/md5/4.sha512-p.chk OLD_FILES+=usr/tests/sbin/md5/4.sha512sum-p.chk OLD_FILES+=usr/tests/sbin/md5/5.inp OLD_FILES+=usr/tests/sbin/md5/5.sha512-p.chk OLD_FILES+=usr/tests/sbin/md5/5.sha512sum-p.chk OLD_FILES+=usr/tests/sbin/md5/6.inp OLD_FILES+=usr/tests/sbin/md5/6.sha512-p.chk OLD_FILES+=usr/tests/sbin/md5/6.sha512sum-p.chk OLD_FILES+=usr/tests/sbin/md5/7.inp OLD_FILES+=usr/tests/sbin/md5/7.sha512-p.chk OLD_FILES+=usr/tests/sbin/md5/7.sha512sum-p.chk OLD_FILES+=usr/tests/sbin/md5/8.inp OLD_FILES+=usr/tests/sbin/md5/8.sha512-p.chk OLD_FILES+=usr/tests/sbin/md5/8.sha512sum-p.chk OLD_FILES+=usr/tests/sbin/md5/algorithms.txt OLD_FILES+=usr/tests/sbin/md5/bsd-c-test OLD_FILES+=usr/tests/sbin/md5/bsd-p-test OLD_FILES+=usr/tests/sbin/md5/bsd-s-test OLD_FILES+=usr/tests/sbin/md5/coreutils-c-test OLD_FILES+=usr/tests/sbin/md5/md5.digest OLD_FILES+=usr/tests/sbin/md5/md5sum.digest OLD_FILES+=usr/tests/sbin/md5/rmd160.digest OLD_FILES+=usr/tests/sbin/md5/rmd160sum.digest OLD_FILES+=usr/tests/sbin/md5/self-test OLD_FILES+=usr/tests/sbin/md5/self-test.md5.chk OLD_FILES+=usr/tests/sbin/md5/self-test.rmd160.chk OLD_FILES+=usr/tests/sbin/md5/self-test.sh_inp OLD_FILES+=usr/tests/sbin/md5/self-test.sha1.chk OLD_FILES+=usr/tests/sbin/md5/self-test.sha224.chk OLD_FILES+=usr/tests/sbin/md5/self-test.sha256.chk OLD_FILES+=usr/tests/sbin/md5/self-test.sha384.chk OLD_FILES+=usr/tests/sbin/md5/self-test.sha512.chk OLD_FILES+=usr/tests/sbin/md5/self-test.sha512t224.chk OLD_FILES+=usr/tests/sbin/md5/self-test.sha512t256.chk OLD_FILES+=usr/tests/sbin/md5/self-test.skein1024.chk OLD_FILES+=usr/tests/sbin/md5/self-test.skein256.chk OLD_FILES+=usr/tests/sbin/md5/self-test.skein512.chk OLD_FILES+=usr/tests/sbin/md5/sha1.digest OLD_FILES+=usr/tests/sbin/md5/sha1sum.digest OLD_FILES+=usr/tests/sbin/md5/sha224.digest OLD_FILES+=usr/tests/sbin/md5/sha224sum.digest OLD_FILES+=usr/tests/sbin/md5/sha256.digest OLD_FILES+=usr/tests/sbin/md5/sha256sum.digest OLD_FILES+=usr/tests/sbin/md5/sha384.digest OLD_FILES+=usr/tests/sbin/md5/sha384sum.digest OLD_FILES+=usr/tests/sbin/md5/sha512.digest OLD_FILES+=usr/tests/sbin/md5/sha512sum.digest OLD_FILES+=usr/tests/sbin/md5/sha512t224.digest OLD_FILES+=usr/tests/sbin/md5/sha512t224sum.digest OLD_FILES+=usr/tests/sbin/md5/sha512t256.digest OLD_FILES+=usr/tests/sbin/md5/sha512t256sum.digest OLD_FILES+=usr/tests/sbin/md5/skein1024.digest OLD_FILES+=usr/tests/sbin/md5/skein1024sum.digest OLD_FILES+=usr/tests/sbin/md5/skein256.digest OLD_FILES+=usr/tests/sbin/md5/skein256sum.digest OLD_FILES+=usr/tests/sbin/md5/skein512.digest OLD_FILES+=usr/tests/sbin/md5/skein512sum.digest OLD_FILES+=usr/tests/sbin/md5/sum_a.in OLD_FILES+=usr/tests/sbin/md5/sum_b.in OLD_FILES+=usr/tests/sbin/md5/sum_c.in OLD_FILES+=usr/tests/sbin/md5/sum_sums.digest # 20230420: portsnap.8 removed OLD_FILES+=etc/portsnap.conf OLD_FILES+=usr/libexec/make_index OLD_FILES+=usr/sbin/portsnap OLD_FILES+=usr/share/examples/etc/portsnap.conf OLD_FILES+=usr/share/man/man8/portsnap.8.gz # 20230331: libpcap updated to 1.10.3 OLD_FILES+=usr/include/fmtutils.h # 20230329: libcasper libraries moved to /lib MOVED_LIBS+=lib/casper/libcap_dns.so.2 MOVED_LIBS+=lib/casper/libcap_fileargs.so.1 MOVED_LIBS+=lib/casper/libcap_grp.so.1 MOVED_LIBS+=lib/casper/libcap_net.so.1 MOVED_LIBS+=lib/casper/libcap_netdb.so.1 MOVED_LIBS+=lib/casper/libcap_pwd.so.1 MOVED_LIBS+=lib/casper/libcap_sysctl.so.1 MOVED_LIBS+=lib/casper/libcap_sysctl.so.2 MOVED_LIBS+=lib/casper/libcap_syslog.so.1 OLD_DIRS+=lib/casper # 20230324: libvmmapi shlib version bumped to 6 OLD_LIBS+=usr/lib/libvmmapi.so.5 # 20230323: tzdata 2023a imported OLD_FILES+=usr/share/zoneinfo/posixrules # 20230320: vcount.9 removed OLD_FILES+=usr/share/man/man9/count_dev.9.gz OLD_FILES+=usr/share/man/man9/vcount.9.gz # 20230320: case-sensitive conflicts removed OLD_FILES+=usr/tests/bin/pkill/pgrep-F_test OLD_FILES+=usr/tests/bin/pkill/pgrep-LF_test OLD_FILES+=usr/tests/bin/pkill/pgrep-P_test OLD_FILES+=usr/tests/bin/pkill/pgrep-U_test OLD_FILES+=usr/tests/bin/pkill/pkill-F_test OLD_FILES+=usr/tests/bin/pkill/pkill-LF_test OLD_FILES+=usr/tests/bin/pkill/pkill-P_test OLD_FILES+=usr/tests/bin/pkill/pkill-U_test # 20230309: remove remaining ATM support OLD_FILES+=usr/bin/sscop OLD_FILES+=usr/include/netgraph/atm/ng_ccatm.h OLD_FILES+=usr/include/netgraph/atm/ng_sscfu.h OLD_FILES+=usr/include/netgraph/atm/ng_sscop.h OLD_FILES+=usr/include/netgraph/atm/ng_uni.h OLD_FILES+=usr/include/netgraph/atm/ngatmbase.h OLD_FILES+=usr/include/netgraph/ng_atmllc.h OLD_FILES+=usr/include/netnatm/addr.h OLD_FILES+=usr/include/netnatm/api/atmapi.h OLD_FILES+=usr/include/netnatm/api/ccatm.h OLD_FILES+=usr/include/netnatm/api/unisap.h OLD_DIRS+=usr/include/netnatm/api OLD_FILES+=usr/include/netnatm/msg/uni_config.h OLD_FILES+=usr/include/netnatm/msg/uni_hdr.h OLD_FILES+=usr/include/netnatm/msg/uni_ie.h OLD_FILES+=usr/include/netnatm/msg/uni_msg.h OLD_FILES+=usr/include/netnatm/msg/unimsglib.h OLD_FILES+=usr/include/netnatm/msg/uniprint.h OLD_FILES+=usr/include/netnatm/msg/unistruct.h OLD_DIRS+=usr/include/netnatm/msg OLD_FILES+=usr/include/netnatm/saal/sscfu.h OLD_FILES+=usr/include/netnatm/saal/sscfudef.h OLD_FILES+=usr/include/netnatm/saal/sscop.h OLD_FILES+=usr/include/netnatm/saal/sscopdef.h OLD_DIRS+=usr/include/netnatm/saal OLD_FILES+=usr/include/netnatm/sig/uni.h OLD_FILES+=usr/include/netnatm/sig/unidef.h OLD_FILES+=usr/include/netnatm/sig/unisig.h OLD_DIRS+=usr/include/netnatm/sig OLD_FILES+=usr/include/netnatm/unimsg.h OLD_DIRS+=usr/include/netnatm OLD_FILES+=usr/lib/libngatm.a OLD_FILES+=usr/lib/libngatm.so OLD_LIBS+=usr/lib/libngatm.so.4 OLD_FILES+=usr/lib/libngatm_p.a OLD_FILES+=usr/share/man/man1/sscop.1.gz OLD_FILES+=usr/share/man/man3/libngatm.3.gz OLD_FILES+=usr/share/man/man3/uniaddr.3.gz OLD_FILES+=usr/share/man/man3/unifunc.3.gz OLD_FILES+=usr/share/man/man3/unimsg.3.gz OLD_FILES+=usr/share/man/man3/unisap.3.gz OLD_FILES+=usr/share/man/man3/unistruct.3.gz OLD_FILES+=usr/share/man/man4/ng_atmllc.4.gz OLD_FILES+=usr/share/man/man4/ng_ccatm.4.gz OLD_FILES+=usr/share/man/man4/ng_sscfu.4.gz OLD_FILES+=usr/share/man/man4/ng_sscop.4.gz OLD_FILES+=usr/share/man/man4/ng_uni.4.gz OLD_FILES+=usr/share/man/man4/ngatmbase.4.gz # 20230308: machine-id merged into hostid_save OLD_FILES+=etc/rc.d/machine_id # 20230306: remove tzsetwall(3) OLD_FILES+=usr/share/man/man3/tzsetwall.3.gz # 20230208: new clang import which bumps version from 14.0.5 to 15.0.7 OLD_FILES+=usr/lib/clang/14.0.5/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/14.0.5/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/14.0.5/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/14.0.5/include/cuda_wrappers OLD_FILES+=usr/lib/clang/14.0.5/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/14.0.5/include/fuzzer OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/14.0.5/include/openmp_wrappers OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/14.0.5/include/ppc_wrappers OLD_FILES+=usr/lib/clang/14.0.5/include/profile/InstrProfData.inc OLD_FILES+=usr/lib/clang/14.0.5/include/profile/MemProfData.inc OLD_DIRS+=usr/lib/clang/14.0.5/include/profile OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/memprof_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/14.0.5/include/sanitizer OLD_FILES+=usr/lib/clang/14.0.5/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/14.0.5/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/14.0.5/include/xray OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_texture_intrinsics.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/14.0.5/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/14.0.5/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/14.0.5/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/14.0.5/include/adxintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/altivec.h OLD_FILES+=usr/lib/clang/14.0.5/include/ammintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/amxintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm64intr.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm_acle.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm_bf16.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm_cde.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm_cmse.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm_fp16.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm_mve.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm_neon.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm_neon_sve_bridge.h OLD_FILES+=usr/lib/clang/14.0.5/include/arm_sve.h OLD_FILES+=usr/lib/clang/14.0.5/include/armintr.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx2intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512fp16intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlfp16intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avxintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/bmiintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/builtins.h OLD_FILES+=usr/lib/clang/14.0.5/include/cet.h OLD_FILES+=usr/lib/clang/14.0.5/include/cetintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/clwbintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/clzerointrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/cpuid.h OLD_FILES+=usr/lib/clang/14.0.5/include/crc32intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/emmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/f16cintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/float.h OLD_FILES+=usr/lib/clang/14.0.5/include/fma4intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/fmaintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/gfniintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/hexagon_circ_brev_intrinsics.h OLD_FILES+=usr/lib/clang/14.0.5/include/hexagon_protos.h OLD_FILES+=usr/lib/clang/14.0.5/include/hexagon_types.h OLD_FILES+=usr/lib/clang/14.0.5/include/hresetintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/htmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/hvx_hexagon_protos.h OLD_FILES+=usr/lib/clang/14.0.5/include/ia32intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/immintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/inttypes.h OLD_FILES+=usr/lib/clang/14.0.5/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/iso646.h OLD_FILES+=usr/lib/clang/14.0.5/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/limits.h OLD_FILES+=usr/lib/clang/14.0.5/include/lwpintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/mm3dnow.h OLD_FILES+=usr/lib/clang/14.0.5/include/mm_malloc.h OLD_FILES+=usr/lib/clang/14.0.5/include/mmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/module.modulemap OLD_FILES+=usr/lib/clang/14.0.5/include/movdirintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/msa.h OLD_FILES+=usr/lib/clang/14.0.5/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/nmmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/omp-tools.h OLD_FILES+=usr/lib/clang/14.0.5/include/omp.h OLD_FILES+=usr/lib/clang/14.0.5/include/ompt.h OLD_FILES+=usr/lib/clang/14.0.5/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/14.0.5/include/opencl-c.h OLD_FILES+=usr/lib/clang/14.0.5/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/pkuintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/pmmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/popcntintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/riscv_vector.h OLD_FILES+=usr/lib/clang/14.0.5/include/rtmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/s390intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/serializeintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/sgxintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/shaintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/smmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/stdalign.h OLD_FILES+=usr/lib/clang/14.0.5/include/stdarg.h OLD_FILES+=usr/lib/clang/14.0.5/include/stdatomic.h OLD_FILES+=usr/lib/clang/14.0.5/include/stdbool.h OLD_FILES+=usr/lib/clang/14.0.5/include/stddef.h OLD_FILES+=usr/lib/clang/14.0.5/include/stdint.h OLD_FILES+=usr/lib/clang/14.0.5/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/14.0.5/include/tbmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/tgmath.h OLD_FILES+=usr/lib/clang/14.0.5/include/tmmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/uintrintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/unwind.h OLD_FILES+=usr/lib/clang/14.0.5/include/vadefs.h OLD_FILES+=usr/lib/clang/14.0.5/include/vaesintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/varargs.h OLD_FILES+=usr/lib/clang/14.0.5/include/vecintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/14.0.5/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/wmmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/x86intrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/xmmintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/xopintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/14.0.5/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/14.0.5/include OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-powerpc64.so OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-powerpc64le.so OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-riscv64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-riscv64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-riscv64.so OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-riscv64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_static-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_static-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_static-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_static-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-riscv64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-riscv64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-riscv64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-riscv64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-riscv64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-riscv64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-basic-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-fdr-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-profiling-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/14.0.5/lib/freebsd OLD_DIRS+=usr/lib/clang/14.0.5/lib OLD_FILES+=usr/lib/clang/14.0.5/share/asan_ignorelist.txt OLD_FILES+=usr/lib/clang/14.0.5/share/cfi_ignorelist.txt OLD_FILES+=usr/lib/clang/14.0.5/share/msan_ignorelist.txt OLD_DIRS+=usr/lib/clang/14.0.5/share OLD_DIRS+=usr/lib/clang/14.0.5 # 20230208: new libc++ import which bumps version from 14.0.5 to 15.0.7 OLD_FILES+=usr/include/c++/v1/__functional_base OLD_FILES+=usr/include/c++/v1/__libcpp_version OLD_FILES+=usr/include/c++/v1/__nullptr OLD_FILES+=usr/include/c++/v1/__string OLD_FILES+=usr/include/c++/v1/experimental/filesystem # 20230203: loader help files renamed OLD_FILES+=boot/loader.help # 20230201: timeout moved from /usr/bin to /bin OLD_FILES+=usr/tests/usr.bin/timeout/Kyuafile OLD_FILES+=usr/tests/usr.bin/timeout/timeout_test # 20230124: rtalloc.9 removed OLD_FILES+=usr/share/man/man9/rtalloc.9.gz OLD_FILES+=usr/share/man/man9/rtalloc_fib.9.gz OLD_FILES+=usr/share/man/man9/rtalloc_ign.9.gz OLD_FILES+=usr/share/man/man9/rtalloc_ign_fib.9.gz OLD_FILES+=usr/share/man/man9/rtalloc1.9.gz OLD_FILES+=usr/share/man/man9/rtalloc1_fib.9.gz OLD_FILES+=usr/share/man/man9/rtfree.9.gz OLD_FILES+=usr/share/man/man9/RT_ADDREF.9.gz OLD_FILES+=usr/share/man/man9/RT_LOCK.9.gz OLD_FILES+=usr/share/man/man9/RT_REMREF.9.gz OLD_FILES+=usr/share/man/man9/RT_RTFREE.9.gz OLD_FILES+=usr/share/man/man9/RT_UNLOCK.9.gz OLD_FILES+=usr/share/man/man9/RTFREE.9.gz OLD_FILES+=usr/share/man/man9/RTFREE_LOCKED.9.gz # 20230123: PCBGROUP.9 removed OLD_FILES+=usr/share/man/man9/PCBGROUP.9.gz OLD_FILES+=usr/share/man/man9/in_pcbgroup_byhash.9.gz OLD_FILES+=usr/share/man/man9/in_pcbgroup_byinpcb.9.gz OLD_FILES+=usr/share/man/man9/in_pcbgroup_destroy.9.gz OLD_FILES+=usr/share/man/man9/in_pcbgroup_enabled.9.gz OLD_FILES+=usr/share/man/man9/in_pcbgroup_init.9.gz OLD_FILES+=usr/share/man/man9/in_pcbgroup_remove.9.gz OLD_FILES+=usr/share/man/man9/in_pcbgroup_update.9.gz OLD_FILES+=usr/share/man/man9/in_pcbgroup_update_mbuf.9.gz OLD_FILES+=usr/share/man/man9/in6_pcbgroup_byhash.9.gz # 20221214: TCPDEBUG removed OLD_FILES+=usr/include/netinet/tcp_debug.h # 20221213: remove sync serial drivers and utilities OLD_FILES+=sbin/sconfig OLD_FILES+=usr/share/man/man4/ce.4.gz OLD_FILES+=usr/share/man/man4/cp.4.gz OLD_FILES+=usr/share/man/man8/sconfig.8.gz # 20221202: remove trpt(8) OLD_FILES+=usr/sbin/trpt OLD_FILES+=usr/share/man/man8/trpt.8.gz # 20221117: remove typo'd man page link OLD_FILES+=usr/share/man/man9/vm_map_wire_mapped.9.gz # 20221114: remove othermta OLD_FILES+=etc/rc.d/othermta # 20221109: remove rc.sendmail(8) OLD_FILES+=etc/rc.sendmail OLD_FILES+=usr/share/man/man8/rc.sendmail.8.gz # 20221015: update the ithread(9) man page OLD_FILES+=usr/share/man/man9/ithread.9.gz OLD_FILES+=usr/share/man/man9/ithread_add_handler.9.gz OLD_FILES+=usr/share/man/man9/ithread_create.9.gz OLD_FILES+=usr/share/man/man9/ithread_destroy.9.gz OLD_FILES+=usr/share/man/man9/ithread_priority.9.gz OLD_FILES+=usr/share/man/man9/ithread_remove_handler.9.gz OLD_FILES+=usr/share/man/man9/ithread_schedule.9.gz # 20221012: remove nls support from sort OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/sort.cat # 20221003: ip6protosw.h removed OLD_FILES+=usr/include/netinet6/ip6protosw.h # 20221001: deorbit opie OLD_FILES+=etc/opieaccess OLD_FILES+=etc/opiekeys OLD_FILES+=usr/bin/opieinfo OLD_FILES+=usr/bin/opiekey OLD_FILES+=usr/bin/opiepasswd OLD_FILES+=usr/bin/otp-md4 OLD_FILES+=usr/bin/otp-md5 OLD_FILES+=usr/bin/otp-sha1 OLD_FILES+=usr/include/opie.h OLD_FILES+=usr/lib/libopie.a OLD_FILES+=usr/lib/libopie.so OLD_LIBS+=usr/lib/libopie.so.8 OLD_FILES+=usr/lib/libopie_p.a OLD_FILES+=usr/lib/pam_opie.so OLD_LIBS+=usr/lib/pam_opie.so.6 OLD_FILES+=usr/lib/pam_opieaccess.so OLD_LIBS+=usr/lib/pam_opieaccess.so.6 OLD_FILES+=usr/share/man/man1/opieinfo.1.gz OLD_FILES+=usr/share/man/man1/opiekey.1.gz OLD_FILES+=usr/share/man/man1/opiepasswd.1.gz OLD_FILES+=usr/share/man/man1/otp-md4.1.gz OLD_FILES+=usr/share/man/man1/otp-md5.1.gz OLD_FILES+=usr/share/man/man1/otp-sha1.1.gz OLD_FILES+=usr/share/man/man4/opie.4.gz OLD_FILES+=usr/share/man/man4/skey.4.gz OLD_FILES+=usr/share/man/man5/opieaccess.5.gz OLD_FILES+=usr/share/man/man5/opiekeys.5.gz OLD_FILES+=usr/share/man/man8/pam_opie.8.gz OLD_FILES+=usr/share/man/man8/pam_opieaccess.8.gz # 20220928: telnetd(8) removed OLD_FILES+=etc/pam.d/telnetd OLD_FILES+=usr/libexec/telnetd OLD_FILES+=usr/share/man/man8/telnetd.8.gz # 20220914: domain(9) updated OLD_FILES+=usr/share/man/man9/domain_init.9.gz OLD_FILES+=usr/share/man/man9/pfctlinput.9.gz OLD_FILES+=usr/share/man/man9/pffinddomain.9.gz OLD_FILES+=usr/share/man/man9/pffindproto.9.gz OLD_FILES+=usr/share/man/man9/pffindtype.9.gz # 20220825: awk tests moved to subdirs OLD_FILES+=usr/tests/usr.bin/awk/awk_test OLD_FILES+=usr/tests/usr.bin/awk/d_assign_NF.awk OLD_FILES+=usr/tests/usr.bin/awk/d_assign_NF.in OLD_FILES+=usr/tests/usr.bin/awk/d_assign_NF.out OLD_FILES+=usr/tests/usr.bin/awk/d_big_regexp.awk OLD_FILES+=usr/tests/usr.bin/awk/d_big_regexp.in OLD_FILES+=usr/tests/usr.bin/awk/d_big_regexp.out OLD_FILES+=usr/tests/usr.bin/awk/d_end1.awk OLD_FILES+=usr/tests/usr.bin/awk/d_end1.in OLD_FILES+=usr/tests/usr.bin/awk/d_end1.out OLD_FILES+=usr/tests/usr.bin/awk/d_end2.awk OLD_FILES+=usr/tests/usr.bin/awk/d_end2.in OLD_FILES+=usr/tests/usr.bin/awk/d_end2.out OLD_FILES+=usr/tests/usr.bin/awk/d_period.awk OLD_FILES+=usr/tests/usr.bin/awk/d_period.in OLD_FILES+=usr/tests/usr.bin/awk/d_period.out OLD_FILES+=usr/tests/usr.bin/awk/d_string1.awk OLD_FILES+=usr/tests/usr.bin/awk/d_string1.out OLD_FILES+=usr/tests/usr.bin/awk/d_tolower.awk OLD_FILES+=usr/tests/usr.bin/awk/d_tolower.in OLD_FILES+=usr/tests/usr.bin/awk/d_tolower.out OLD_FILES+=usr/tests/usr.bin/awk/d_toupper.awk OLD_FILES+=usr/tests/usr.bin/awk/d_toupper.in OLD_FILES+=usr/tests/usr.bin/awk/d_toupper.out # 20220820: remove knlist_init_rw_reader() OLD_FILES+=usr/share/man/man9/knlist_init_rw_reader.9.gz # 20220813: minigzip(1) removed in favor of gzip(1) OLD_FILES+=usr/bin/minigzip OLD_FILES+=usr/share/man/man1/minigzip.1.gz # 20220811: MP_WATCHDOG removed OLD_FILES+=usr/include/machine/mp_watchdog.h # 20220811: new iconv encoder trait added OLD_LIBS+=usr/lib/i18n/libBIG5.so.4 OLD_LIBS+=usr/lib/i18n/libDECHanyu.so.4 OLD_LIBS+=usr/lib/i18n/libEUC.so.4 OLD_LIBS+=usr/lib/i18n/libEUCTW.so.4 OLD_LIBS+=usr/lib/i18n/libGBK2K.so.4 OLD_LIBS+=usr/lib/i18n/libHZ.so.4 OLD_LIBS+=usr/lib/i18n/libISO2022.so.4 OLD_LIBS+=usr/lib/i18n/libJOHAB.so.4 OLD_LIBS+=usr/lib/i18n/libMSKanji.so.4 OLD_LIBS+=usr/lib/i18n/libUES.so.4 OLD_LIBS+=usr/lib/i18n/libUTF1632.so.4 OLD_LIBS+=usr/lib/i18n/libUTF7.so.4 OLD_LIBS+=usr/lib/i18n/libUTF8.so.4 OLD_LIBS+=usr/lib/i18n/libVIQR.so.4 OLD_LIBS+=usr/lib/i18n/libZW.so.4 OLD_LIBS+=usr/lib/i18n/libiconv_none.so.4 OLD_LIBS+=usr/lib/i18n/libiconv_std.so.4 OLD_LIBS+=usr/lib/i18n/libmapper_646.so.4 OLD_LIBS+=usr/lib/i18n/libmapper_none.so.4 OLD_LIBS+=usr/lib/i18n/libmapper_parallel.so.4 OLD_LIBS+=usr/lib/i18n/libmapper_serial.so.4 OLD_LIBS+=usr/lib/i18n/libmapper_std.so.4 OLD_LIBS+=usr/lib/i18n/libmapper_zone.so.4 # 20220811: raw socket layer removed OLD_FILES+=usr/include/net/raw_cb.h # 20220721: libnv version bumps OLD_LIBS+=lib/libnv.so.0 # 20220624: unix_passfd_test -> unix_passfd_stream/unix_passfd_dgram OLD_FILES+=usr/tests/sys/kern/unix_passfd_test # 20220621: ISA sound card drivers removed OLD_FILES+=usr/share/man/man4/snd_ad1816.4.gz OLD_FILES+=usr/share/man/man4/snd_ess.4.gz OLD_FILES+=usr/share/man/man4/snd_gusc.4.gz OLD_FILES+=usr/share/man/man4/snd_mss.4.gz OLD_FILES+=usr/share/man/man4/snd_sb16.4.gz OLD_FILES+=usr/share/man/man4/snd_sb8.4.gz OLD_FILES+=usr/share/man/man4/snd_sbc.4.gz # 20220612: new clang import which bumps version from 14.0.4 to 14.0.5 OLD_FILES+=usr/lib/clang/14.0.4/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/14.0.4/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/14.0.4/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/14.0.4/include/cuda_wrappers OLD_FILES+=usr/lib/clang/14.0.4/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/14.0.4/include/fuzzer OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/14.0.4/include/openmp_wrappers OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/14.0.4/include/ppc_wrappers OLD_FILES+=usr/lib/clang/14.0.4/include/profile/InstrProfData.inc OLD_FILES+=usr/lib/clang/14.0.4/include/profile/MemProfData.inc OLD_DIRS+=usr/lib/clang/14.0.4/include/profile OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/memprof_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/14.0.4/include/sanitizer OLD_FILES+=usr/lib/clang/14.0.4/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/14.0.4/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/14.0.4/include/xray OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_texture_intrinsics.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/14.0.4/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/14.0.4/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/14.0.4/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/14.0.4/include/adxintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/altivec.h OLD_FILES+=usr/lib/clang/14.0.4/include/ammintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/amxintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm64intr.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm_acle.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm_bf16.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm_cde.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm_cmse.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm_fp16.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm_mve.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm_neon.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm_neon_sve_bridge.h OLD_FILES+=usr/lib/clang/14.0.4/include/arm_sve.h OLD_FILES+=usr/lib/clang/14.0.4/include/armintr.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx2intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512fp16intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlfp16intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avxintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/bmiintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/builtins.h OLD_FILES+=usr/lib/clang/14.0.4/include/cet.h OLD_FILES+=usr/lib/clang/14.0.4/include/cetintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/clwbintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/clzerointrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/cpuid.h OLD_FILES+=usr/lib/clang/14.0.4/include/crc32intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/emmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/f16cintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/float.h OLD_FILES+=usr/lib/clang/14.0.4/include/fma4intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/fmaintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/gfniintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/hexagon_circ_brev_intrinsics.h OLD_FILES+=usr/lib/clang/14.0.4/include/hexagon_protos.h OLD_FILES+=usr/lib/clang/14.0.4/include/hexagon_types.h OLD_FILES+=usr/lib/clang/14.0.4/include/hresetintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/htmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/hvx_hexagon_protos.h OLD_FILES+=usr/lib/clang/14.0.4/include/ia32intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/immintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/inttypes.h OLD_FILES+=usr/lib/clang/14.0.4/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/iso646.h OLD_FILES+=usr/lib/clang/14.0.4/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/limits.h OLD_FILES+=usr/lib/clang/14.0.4/include/lwpintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/mm3dnow.h OLD_FILES+=usr/lib/clang/14.0.4/include/mm_malloc.h OLD_FILES+=usr/lib/clang/14.0.4/include/mmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/module.modulemap OLD_FILES+=usr/lib/clang/14.0.4/include/movdirintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/msa.h OLD_FILES+=usr/lib/clang/14.0.4/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/nmmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/omp-tools.h OLD_FILES+=usr/lib/clang/14.0.4/include/omp.h OLD_FILES+=usr/lib/clang/14.0.4/include/ompt.h OLD_FILES+=usr/lib/clang/14.0.4/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/14.0.4/include/opencl-c.h OLD_FILES+=usr/lib/clang/14.0.4/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/pkuintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/pmmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/popcntintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/riscv_vector.h OLD_FILES+=usr/lib/clang/14.0.4/include/rtmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/s390intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/serializeintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/sgxintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/shaintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/smmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/stdalign.h OLD_FILES+=usr/lib/clang/14.0.4/include/stdarg.h OLD_FILES+=usr/lib/clang/14.0.4/include/stdatomic.h OLD_FILES+=usr/lib/clang/14.0.4/include/stdbool.h OLD_FILES+=usr/lib/clang/14.0.4/include/stddef.h OLD_FILES+=usr/lib/clang/14.0.4/include/stdint.h OLD_FILES+=usr/lib/clang/14.0.4/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/14.0.4/include/tbmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/tgmath.h OLD_FILES+=usr/lib/clang/14.0.4/include/tmmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/uintrintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/unwind.h OLD_FILES+=usr/lib/clang/14.0.4/include/vadefs.h OLD_FILES+=usr/lib/clang/14.0.4/include/vaesintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/varargs.h OLD_FILES+=usr/lib/clang/14.0.4/include/vecintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/14.0.4/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/wmmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/x86intrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/xmmintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/xopintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/14.0.4/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/14.0.4/include OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_static-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_static-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/14.0.4/lib/freebsd OLD_DIRS+=usr/lib/clang/14.0.4/lib/share OLD_DIRS+=usr/lib/clang/14.0.4/lib OLD_FILES+=usr/lib/clang/14.0.4/share/asan_ignorelist.txt OLD_FILES+=usr/lib/clang/14.0.4/share/cfi_ignorelist.txt OLD_FILES+=usr/lib/clang/14.0.4/share/msan_ignorelist.txt OLD_DIRS+=usr/lib/clang/14.0.4/share OLD_DIRS+=usr/lib/clang/14.0.4 # 20220605: new clang import which bumps version from 14.0.3 to 14.0.4 OLD_FILES+=usr/lib/clang/14.0.3/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/14.0.3/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/14.0.3/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/14.0.3/include/cuda_wrappers OLD_FILES+=usr/lib/clang/14.0.3/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/14.0.3/include/fuzzer OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/14.0.3/include/openmp_wrappers OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/14.0.3/include/ppc_wrappers OLD_FILES+=usr/lib/clang/14.0.3/include/profile/InstrProfData.inc OLD_FILES+=usr/lib/clang/14.0.3/include/profile/MemProfData.inc OLD_DIRS+=usr/lib/clang/14.0.3/include/profile OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/memprof_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/14.0.3/include/sanitizer OLD_FILES+=usr/lib/clang/14.0.3/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/14.0.3/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/14.0.3/include/xray OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_texture_intrinsics.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/14.0.3/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/14.0.3/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/14.0.3/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/14.0.3/include/adxintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/altivec.h OLD_FILES+=usr/lib/clang/14.0.3/include/ammintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/amxintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm64intr.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm_acle.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm_bf16.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm_cde.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm_cmse.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm_fp16.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm_mve.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm_neon.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm_neon_sve_bridge.h OLD_FILES+=usr/lib/clang/14.0.3/include/arm_sve.h OLD_FILES+=usr/lib/clang/14.0.3/include/armintr.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx2intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512fp16intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlfp16intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avxintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/bmiintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/builtins.h OLD_FILES+=usr/lib/clang/14.0.3/include/cet.h OLD_FILES+=usr/lib/clang/14.0.3/include/cetintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/clwbintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/clzerointrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/cpuid.h OLD_FILES+=usr/lib/clang/14.0.3/include/crc32intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/emmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/f16cintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/float.h OLD_FILES+=usr/lib/clang/14.0.3/include/fma4intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/fmaintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/gfniintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/hexagon_circ_brev_intrinsics.h OLD_FILES+=usr/lib/clang/14.0.3/include/hexagon_protos.h OLD_FILES+=usr/lib/clang/14.0.3/include/hexagon_types.h OLD_FILES+=usr/lib/clang/14.0.3/include/hresetintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/htmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/hvx_hexagon_protos.h OLD_FILES+=usr/lib/clang/14.0.3/include/ia32intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/immintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/inttypes.h OLD_FILES+=usr/lib/clang/14.0.3/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/iso646.h OLD_FILES+=usr/lib/clang/14.0.3/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/limits.h OLD_FILES+=usr/lib/clang/14.0.3/include/lwpintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/mm3dnow.h OLD_FILES+=usr/lib/clang/14.0.3/include/mm_malloc.h OLD_FILES+=usr/lib/clang/14.0.3/include/mmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/module.modulemap OLD_FILES+=usr/lib/clang/14.0.3/include/movdirintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/msa.h OLD_FILES+=usr/lib/clang/14.0.3/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/nmmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/omp-tools.h OLD_FILES+=usr/lib/clang/14.0.3/include/omp.h OLD_FILES+=usr/lib/clang/14.0.3/include/ompt.h OLD_FILES+=usr/lib/clang/14.0.3/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/14.0.3/include/opencl-c.h OLD_FILES+=usr/lib/clang/14.0.3/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/pkuintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/pmmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/popcntintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/riscv_vector.h OLD_FILES+=usr/lib/clang/14.0.3/include/rtmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/s390intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/serializeintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/sgxintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/shaintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/smmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/stdalign.h OLD_FILES+=usr/lib/clang/14.0.3/include/stdarg.h OLD_FILES+=usr/lib/clang/14.0.3/include/stdatomic.h OLD_FILES+=usr/lib/clang/14.0.3/include/stdbool.h OLD_FILES+=usr/lib/clang/14.0.3/include/stddef.h OLD_FILES+=usr/lib/clang/14.0.3/include/stdint.h OLD_FILES+=usr/lib/clang/14.0.3/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/14.0.3/include/tbmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/tgmath.h OLD_FILES+=usr/lib/clang/14.0.3/include/tmmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/uintrintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/unwind.h OLD_FILES+=usr/lib/clang/14.0.3/include/vadefs.h OLD_FILES+=usr/lib/clang/14.0.3/include/vaesintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/varargs.h OLD_FILES+=usr/lib/clang/14.0.3/include/vecintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/14.0.3/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/wmmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/x86intrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/xmmintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/xopintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/14.0.3/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/14.0.3/include OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_static-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_static-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/14.0.3/lib/freebsd OLD_DIRS+=usr/lib/clang/14.0.3/lib/share OLD_DIRS+=usr/lib/clang/14.0.3/lib OLD_FILES+=usr/lib/clang/14.0.3/share/asan_ignorelist.txt OLD_FILES+=usr/lib/clang/14.0.3/share/cfi_ignorelist.txt OLD_FILES+=usr/lib/clang/14.0.3/share/msan_ignorelist.txt OLD_DIRS+=usr/lib/clang/14.0.3/share OLD_DIRS+=usr/lib/clang/14.0.3 # 20220524: libkqueue test updates OLD_FILES+=usr/tests/sys/kqueue/libkqueue/kqtest # 20220514: new clang import which bumps version from 13.0.0 to 14.0.3 OLD_FILES+=usr/lib/clang/13.0.0/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/13.0.0/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/13.0.0/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/13.0.0/include/cuda_wrappers OLD_FILES+=usr/lib/clang/13.0.0/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/13.0.0/include/fuzzer OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/13.0.0/include/openmp_wrappers OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/13.0.0/include/ppc_wrappers OLD_FILES+=usr/lib/clang/13.0.0/include/profile/InstrProfData.inc OLD_DIRS+=usr/lib/clang/13.0.0/include/profile OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/13.0.0/include/sanitizer OLD_FILES+=usr/lib/clang/13.0.0/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/13.0.0/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/13.0.0/include/xray OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/13.0.0/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/13.0.0/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/13.0.0/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/13.0.0/include/adxintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/altivec.h OLD_FILES+=usr/lib/clang/13.0.0/include/ammintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/amxintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/arm64intr.h OLD_FILES+=usr/lib/clang/13.0.0/include/arm_acle.h OLD_FILES+=usr/lib/clang/13.0.0/include/arm_bf16.h OLD_FILES+=usr/lib/clang/13.0.0/include/arm_cde.h OLD_FILES+=usr/lib/clang/13.0.0/include/arm_cmse.h OLD_FILES+=usr/lib/clang/13.0.0/include/arm_fp16.h OLD_FILES+=usr/lib/clang/13.0.0/include/arm_mve.h OLD_FILES+=usr/lib/clang/13.0.0/include/arm_neon.h OLD_FILES+=usr/lib/clang/13.0.0/include/arm_sve.h OLD_FILES+=usr/lib/clang/13.0.0/include/armintr.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx2intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avxintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/bmiintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/builtins.h OLD_FILES+=usr/lib/clang/13.0.0/include/cet.h OLD_FILES+=usr/lib/clang/13.0.0/include/cetintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/clwbintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/clzerointrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/cpuid.h OLD_FILES+=usr/lib/clang/13.0.0/include/emmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/f16cintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/float.h OLD_FILES+=usr/lib/clang/13.0.0/include/fma4intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/fmaintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/gfniintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/hexagon_circ_brev_intrinsics.h OLD_FILES+=usr/lib/clang/13.0.0/include/hexagon_protos.h OLD_FILES+=usr/lib/clang/13.0.0/include/hexagon_types.h OLD_FILES+=usr/lib/clang/13.0.0/include/hresetintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/htmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/hvx_hexagon_protos.h OLD_FILES+=usr/lib/clang/13.0.0/include/ia32intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/immintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/inttypes.h OLD_FILES+=usr/lib/clang/13.0.0/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/iso646.h OLD_FILES+=usr/lib/clang/13.0.0/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/limits.h OLD_FILES+=usr/lib/clang/13.0.0/include/lwpintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/mm3dnow.h OLD_FILES+=usr/lib/clang/13.0.0/include/mm_malloc.h OLD_FILES+=usr/lib/clang/13.0.0/include/mmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/module.modulemap OLD_FILES+=usr/lib/clang/13.0.0/include/movdirintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/msa.h OLD_FILES+=usr/lib/clang/13.0.0/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/nmmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/omp-tools.h OLD_FILES+=usr/lib/clang/13.0.0/include/omp.h OLD_FILES+=usr/lib/clang/13.0.0/include/ompt.h OLD_FILES+=usr/lib/clang/13.0.0/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/13.0.0/include/opencl-c.h OLD_FILES+=usr/lib/clang/13.0.0/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/pkuintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/pmmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/popcntintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/riscv_vector.h OLD_FILES+=usr/lib/clang/13.0.0/include/rtmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/s390intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/serializeintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/sgxintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/shaintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/smmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/stdalign.h OLD_FILES+=usr/lib/clang/13.0.0/include/stdarg.h OLD_FILES+=usr/lib/clang/13.0.0/include/stdatomic.h OLD_FILES+=usr/lib/clang/13.0.0/include/stdbool.h OLD_FILES+=usr/lib/clang/13.0.0/include/stddef.h OLD_FILES+=usr/lib/clang/13.0.0/include/stdint.h OLD_FILES+=usr/lib/clang/13.0.0/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/13.0.0/include/tbmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/tgmath.h OLD_FILES+=usr/lib/clang/13.0.0/include/tmmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/uintrintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/unwind.h OLD_FILES+=usr/lib/clang/13.0.0/include/vadefs.h OLD_FILES+=usr/lib/clang/13.0.0/include/vaesintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/varargs.h OLD_FILES+=usr/lib/clang/13.0.0/include/vecintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/13.0.0/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/wmmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/x86intrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/xmmintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/xopintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/13.0.0/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/13.0.0/include OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/13.0.0/lib/freebsd OLD_DIRS+=usr/lib/clang/13.0.0/lib OLD_DIRS+=usr/lib/clang/13.0.0 # 20220514: new libc++ import which bumps version from 13.0.0 to 14.0.3 OLD_FILES+=usr/include/c++/v1/__function_like.h OLD_FILES+=usr/include/c++/v1/__memory/pointer_safety.h OLD_FILES+=usr/include/c++/v1/__utility/__decay_copy.h # 20220418: uudecode merged into uuencode and renamed to bintrans OLD_FILES+=usr/lib/debug/usr/bin/uuencode.debug OLD_FILES+=usr/lib/debug/usr/bin/uudecode.debug OLD_FILES+=usr/tests/usr.bin/uuencode/Kyuafile OLD_FILES+=usr/tests/usr.bin/uuencode/legacy_test OLD_FILES+=usr/tests/usr.bin/uuencode/regress.base64.in OLD_FILES+=usr/tests/usr.bin/uuencode/regress.traditional.out OLD_FILES+=usr/tests/usr.bin/uuencode/regress.traditional.in OLD_FILES+=usr/tests/usr.bin/uuencode/regress.out OLD_FILES+=usr/tests/usr.bin/uuencode/regress.sh OLD_FILES+=usr/tests/usr.bin/uuencode/regress.in OLD_FILES+=usr/tests/usr.bin/uuencode/regress.153276.in OLD_FILES+=usr/tests/usr.bin/uuencode/regress.base64.out OLD_FILES+=usr/tests/usr.bin/uuencode/regress.153276.out OLD_FILES+=usr/tests/usr.bin/uudecode/regress.base64.in OLD_FILES+=usr/tests/usr.bin/uudecode/Kyuafile OLD_FILES+=usr/tests/usr.bin/uudecode/regress.out OLD_FILES+=usr/tests/usr.bin/uudecode/regress.sh OLD_FILES+=usr/tests/usr.bin/uudecode/regress.153276.out OLD_FILES+=usr/tests/usr.bin/uudecode/regress.traditional.in OLD_FILES+=usr/tests/usr.bin/uudecode/legacy_test OLD_FILES+=usr/tests/usr.bin/uudecode/regress.153276.in OLD_DIRS+=usr/tests/usr.bin/uuencode OLD_DIRS+=usr/tests/usr.bin/uudecode # 20220318: snd_ds1 and snd_maestro drivers removed OLD_FILES+=usr/share/man/man4/snd_ds1.4.gz OLD_FILES+=usr/share/man/man4/snd_maestro.4.gz # 20220307: remove 330.news OLD_FILES+=etc/periodic/daily/330.news # 20220210: unwind.h moved to /usr/include OLD_FILES+=usr/include/c++/v1/unwind-arm.h OLD_FILES+=usr/include/c++/v1/unwind-itanium.h OLD_FILES+=usr/include/c++/v1/unwind.h # 20220128: mips pmc events removed OLD_FILES+=usr/share/man/man3/pmc.mips24k.3.gz OLD_FILES+=usr/share/man/man3/pmc.octeon.3.gz # 20220127: terasic_mtl.4 removed OLD_FILES+=usr/share/man/man4/terasic_mtl.4.gz # 20211229: libc++ moved to /lib MOVED_LIBS+=usr/lib/libc++.so.1 # 20211221: efi_set_variables_supported.3 should be efi_variables_supported.3 OLD_FILES+=usr/share/man/man3/efi_set_variables_supported.3.gz # 20211218: meteor.4 removed, see also 20200301 entry below OLD_FILES+=usr/share/man/man4/meteor.4.gz # 20211125: Old SCSI drivers removed OLD_FILES+=usr/include/dev/ic/esp.h OLD_FILES+=usr/share/man/man4/amr.4.gz OLD_FILES+=usr/share/man/man4/esp.4.gz OLD_FILES+=usr/share/man/man4/iir.4.gz OLD_FILES+=usr/share/man/man4/mly.4.gz OLD_FILES+=usr/share/man/man4/twa.4.gz # 20211120: kernel_vmount function removed OLD_FILES+=usr/share/man/man9/kernel_vmount.9.gz # 20211115: vm_page busy functions removed OLD_FILES+=usr/share/man/man9/vm_page_sbusy.9.gz OLD_FILES+=usr/share/man/man9/vm_page_xbusy.9.gz OLD_FILES+=usr/share/man/man9/vm_page_sleep_if_busy.9.gz # 20211113: new clang import which bumps version from 12.0.1 to 13.0.0 OLD_FILES+=usr/lib/clang/12.0.1/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/12.0.1/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/12.0.1/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/12.0.1/include/cuda_wrappers OLD_FILES+=usr/lib/clang/12.0.1/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/12.0.1/include/fuzzer OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/12.0.1/include/openmp_wrappers OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/12.0.1/include/ppc_wrappers OLD_FILES+=usr/lib/clang/12.0.1/include/profile/InstrProfData.inc OLD_DIRS+=usr/lib/clang/12.0.1/include/profile OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/12.0.1/include/sanitizer OLD_FILES+=usr/lib/clang/12.0.1/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/12.0.1/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/12.0.1/include/xray OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/12.0.1/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/12.0.1/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/12.0.1/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/12.0.1/include/adxintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/altivec.h OLD_FILES+=usr/lib/clang/12.0.1/include/ammintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/amxintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/arm64intr.h OLD_FILES+=usr/lib/clang/12.0.1/include/arm_acle.h OLD_FILES+=usr/lib/clang/12.0.1/include/arm_bf16.h OLD_FILES+=usr/lib/clang/12.0.1/include/arm_cde.h OLD_FILES+=usr/lib/clang/12.0.1/include/arm_cmse.h OLD_FILES+=usr/lib/clang/12.0.1/include/arm_fp16.h OLD_FILES+=usr/lib/clang/12.0.1/include/arm_mve.h OLD_FILES+=usr/lib/clang/12.0.1/include/arm_neon.h OLD_FILES+=usr/lib/clang/12.0.1/include/arm_sve.h OLD_FILES+=usr/lib/clang/12.0.1/include/armintr.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx2intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avxintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/bmiintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/cet.h OLD_FILES+=usr/lib/clang/12.0.1/include/cetintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/clwbintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/clzerointrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/cpuid.h OLD_FILES+=usr/lib/clang/12.0.1/include/emmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/f16cintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/float.h OLD_FILES+=usr/lib/clang/12.0.1/include/fma4intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/fmaintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/gfniintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/hresetintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/htmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/ia32intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/immintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/inttypes.h OLD_FILES+=usr/lib/clang/12.0.1/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/iso646.h OLD_FILES+=usr/lib/clang/12.0.1/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/limits.h OLD_FILES+=usr/lib/clang/12.0.1/include/lwpintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/mm3dnow.h OLD_FILES+=usr/lib/clang/12.0.1/include/mm_malloc.h OLD_FILES+=usr/lib/clang/12.0.1/include/mmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/module.modulemap OLD_FILES+=usr/lib/clang/12.0.1/include/movdirintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/msa.h OLD_FILES+=usr/lib/clang/12.0.1/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/nmmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/omp-tools.h OLD_FILES+=usr/lib/clang/12.0.1/include/omp.h OLD_FILES+=usr/lib/clang/12.0.1/include/ompt.h OLD_FILES+=usr/lib/clang/12.0.1/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/12.0.1/include/opencl-c.h OLD_FILES+=usr/lib/clang/12.0.1/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/pkuintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/pmmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/popcntintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/rtmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/s390intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/serializeintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/sgxintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/shaintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/smmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/stdalign.h OLD_FILES+=usr/lib/clang/12.0.1/include/stdarg.h OLD_FILES+=usr/lib/clang/12.0.1/include/stdatomic.h OLD_FILES+=usr/lib/clang/12.0.1/include/stdbool.h OLD_FILES+=usr/lib/clang/12.0.1/include/stddef.h OLD_FILES+=usr/lib/clang/12.0.1/include/stdint.h OLD_FILES+=usr/lib/clang/12.0.1/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/12.0.1/include/tbmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/tgmath.h OLD_FILES+=usr/lib/clang/12.0.1/include/tmmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/uintrintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/unwind.h OLD_FILES+=usr/lib/clang/12.0.1/include/vadefs.h OLD_FILES+=usr/lib/clang/12.0.1/include/vaesintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/varargs.h OLD_FILES+=usr/lib/clang/12.0.1/include/vecintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/12.0.1/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/wmmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/x86intrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/xmmintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/xopintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/12.0.1/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/12.0.1/include OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/12.0.1/lib/freebsd OLD_DIRS+=usr/lib/clang/12.0.1/lib OLD_DIRS+=usr/lib/clang/12.0.1 # 20211113: new libc++ import which bumps version from 12.0.1 to 13.0.0 OLD_FILES+=usr/include/c++/v1/__functional_03 OLD_FILES+=usr/include/c++/v1/__functional_base_03 OLD_FILES+=usr/include/c++/v1/__memory/base.h OLD_FILES+=usr/include/c++/v1/__memory/utilities.h OLD_FILES+=usr/include/c++/v1/__sso_allocator OLD_FILES+=usr/include/c++/v1/tr1/__availability OLD_FILES+=usr/include/c++/v1/tr1/__bit_reference OLD_FILES+=usr/include/c++/v1/tr1/__bits OLD_FILES+=usr/include/c++/v1/tr1/__bsd_locale_defaults.h OLD_FILES+=usr/include/c++/v1/tr1/__bsd_locale_fallbacks.h OLD_FILES+=usr/include/c++/v1/tr1/__config OLD_FILES+=usr/include/c++/v1/tr1/__debug OLD_FILES+=usr/include/c++/v1/tr1/__errc OLD_FILES+=usr/include/c++/v1/tr1/__functional_03 OLD_FILES+=usr/include/c++/v1/tr1/__functional_base OLD_FILES+=usr/include/c++/v1/tr1/__functional_base_03 OLD_FILES+=usr/include/c++/v1/tr1/__hash_table OLD_FILES+=usr/include/c++/v1/tr1/__libcpp_version OLD_FILES+=usr/include/c++/v1/tr1/__locale OLD_FILES+=usr/include/c++/v1/tr1/__mutex_base OLD_FILES+=usr/include/c++/v1/tr1/__node_handle OLD_FILES+=usr/include/c++/v1/tr1/__nullptr OLD_FILES+=usr/include/c++/v1/tr1/__split_buffer OLD_FILES+=usr/include/c++/v1/tr1/__sso_allocator OLD_FILES+=usr/include/c++/v1/tr1/__std_stream OLD_FILES+=usr/include/c++/v1/tr1/__string OLD_FILES+=usr/include/c++/v1/tr1/__threading_support OLD_FILES+=usr/include/c++/v1/tr1/__tree OLD_FILES+=usr/include/c++/v1/tr1/__tuple OLD_FILES+=usr/include/c++/v1/tr1/__undef_macros OLD_FILES+=usr/include/c++/v1/tr1/algorithm OLD_FILES+=usr/include/c++/v1/tr1/any OLD_FILES+=usr/include/c++/v1/tr1/array OLD_FILES+=usr/include/c++/v1/tr1/atomic OLD_FILES+=usr/include/c++/v1/tr1/barrier OLD_FILES+=usr/include/c++/v1/tr1/bit OLD_FILES+=usr/include/c++/v1/tr1/bitset OLD_FILES+=usr/include/c++/v1/tr1/cassert OLD_FILES+=usr/include/c++/v1/tr1/ccomplex OLD_FILES+=usr/include/c++/v1/tr1/cctype OLD_FILES+=usr/include/c++/v1/tr1/cerrno OLD_FILES+=usr/include/c++/v1/tr1/cfenv OLD_FILES+=usr/include/c++/v1/tr1/cfloat OLD_FILES+=usr/include/c++/v1/tr1/charconv OLD_FILES+=usr/include/c++/v1/tr1/chrono OLD_FILES+=usr/include/c++/v1/tr1/cinttypes OLD_FILES+=usr/include/c++/v1/tr1/ciso646 OLD_FILES+=usr/include/c++/v1/tr1/climits OLD_FILES+=usr/include/c++/v1/tr1/clocale OLD_FILES+=usr/include/c++/v1/tr1/cmath OLD_FILES+=usr/include/c++/v1/tr1/codecvt OLD_FILES+=usr/include/c++/v1/tr1/compare OLD_FILES+=usr/include/c++/v1/tr1/complex OLD_FILES+=usr/include/c++/v1/tr1/complex.h OLD_FILES+=usr/include/c++/v1/tr1/concepts OLD_FILES+=usr/include/c++/v1/tr1/condition_variable OLD_FILES+=usr/include/c++/v1/tr1/csetjmp OLD_FILES+=usr/include/c++/v1/tr1/csignal OLD_FILES+=usr/include/c++/v1/tr1/cstdarg OLD_FILES+=usr/include/c++/v1/tr1/cstdbool OLD_FILES+=usr/include/c++/v1/tr1/cstddef OLD_FILES+=usr/include/c++/v1/tr1/cstdint OLD_FILES+=usr/include/c++/v1/tr1/cstdio OLD_FILES+=usr/include/c++/v1/tr1/cstdlib OLD_FILES+=usr/include/c++/v1/tr1/cstring OLD_FILES+=usr/include/c++/v1/tr1/ctgmath OLD_FILES+=usr/include/c++/v1/tr1/ctime OLD_FILES+=usr/include/c++/v1/tr1/ctype.h OLD_FILES+=usr/include/c++/v1/tr1/cwchar OLD_FILES+=usr/include/c++/v1/tr1/cwctype OLD_FILES+=usr/include/c++/v1/tr1/deque OLD_FILES+=usr/include/c++/v1/tr1/errno.h OLD_FILES+=usr/include/c++/v1/tr1/exception OLD_FILES+=usr/include/c++/v1/tr1/execution OLD_FILES+=usr/include/c++/v1/tr1/fenv.h OLD_FILES+=usr/include/c++/v1/tr1/filesystem OLD_FILES+=usr/include/c++/v1/tr1/float.h OLD_FILES+=usr/include/c++/v1/tr1/forward_list OLD_FILES+=usr/include/c++/v1/tr1/fstream OLD_FILES+=usr/include/c++/v1/tr1/functional OLD_FILES+=usr/include/c++/v1/tr1/future OLD_FILES+=usr/include/c++/v1/tr1/initializer_list OLD_FILES+=usr/include/c++/v1/tr1/inttypes.h OLD_FILES+=usr/include/c++/v1/tr1/iomanip OLD_FILES+=usr/include/c++/v1/tr1/ios OLD_FILES+=usr/include/c++/v1/tr1/iosfwd OLD_FILES+=usr/include/c++/v1/tr1/iostream OLD_FILES+=usr/include/c++/v1/tr1/istream OLD_FILES+=usr/include/c++/v1/tr1/iterator OLD_FILES+=usr/include/c++/v1/tr1/latch OLD_FILES+=usr/include/c++/v1/tr1/limits OLD_FILES+=usr/include/c++/v1/tr1/limits.h OLD_FILES+=usr/include/c++/v1/tr1/list OLD_FILES+=usr/include/c++/v1/tr1/locale OLD_FILES+=usr/include/c++/v1/tr1/locale.h OLD_FILES+=usr/include/c++/v1/tr1/map OLD_FILES+=usr/include/c++/v1/tr1/math.h OLD_FILES+=usr/include/c++/v1/tr1/memory OLD_FILES+=usr/include/c++/v1/tr1/mutex OLD_FILES+=usr/include/c++/v1/tr1/new OLD_FILES+=usr/include/c++/v1/tr1/numbers OLD_FILES+=usr/include/c++/v1/tr1/numeric OLD_FILES+=usr/include/c++/v1/tr1/optional OLD_FILES+=usr/include/c++/v1/tr1/ostream OLD_FILES+=usr/include/c++/v1/tr1/queue OLD_FILES+=usr/include/c++/v1/tr1/random OLD_FILES+=usr/include/c++/v1/tr1/ratio OLD_FILES+=usr/include/c++/v1/tr1/regex OLD_FILES+=usr/include/c++/v1/tr1/scoped_allocator OLD_FILES+=usr/include/c++/v1/tr1/semaphore OLD_FILES+=usr/include/c++/v1/tr1/set OLD_FILES+=usr/include/c++/v1/tr1/setjmp.h OLD_FILES+=usr/include/c++/v1/tr1/shared_mutex OLD_FILES+=usr/include/c++/v1/tr1/span OLD_FILES+=usr/include/c++/v1/tr1/sstream OLD_FILES+=usr/include/c++/v1/tr1/stack OLD_FILES+=usr/include/c++/v1/tr1/stdbool.h OLD_FILES+=usr/include/c++/v1/tr1/stddef.h OLD_FILES+=usr/include/c++/v1/tr1/stdexcept OLD_FILES+=usr/include/c++/v1/tr1/stdint.h OLD_FILES+=usr/include/c++/v1/tr1/stdio.h OLD_FILES+=usr/include/c++/v1/tr1/stdlib.h OLD_FILES+=usr/include/c++/v1/tr1/streambuf OLD_FILES+=usr/include/c++/v1/tr1/string OLD_FILES+=usr/include/c++/v1/tr1/string.h OLD_FILES+=usr/include/c++/v1/tr1/string_view OLD_FILES+=usr/include/c++/v1/tr1/strstream OLD_FILES+=usr/include/c++/v1/tr1/system_error OLD_FILES+=usr/include/c++/v1/tr1/tgmath.h OLD_FILES+=usr/include/c++/v1/tr1/thread OLD_FILES+=usr/include/c++/v1/tr1/tuple OLD_FILES+=usr/include/c++/v1/tr1/type_traits OLD_FILES+=usr/include/c++/v1/tr1/typeindex OLD_FILES+=usr/include/c++/v1/tr1/typeinfo OLD_FILES+=usr/include/c++/v1/tr1/unordered_map OLD_FILES+=usr/include/c++/v1/tr1/unordered_set OLD_FILES+=usr/include/c++/v1/tr1/utility OLD_FILES+=usr/include/c++/v1/tr1/valarray OLD_FILES+=usr/include/c++/v1/tr1/variant OLD_FILES+=usr/include/c++/v1/tr1/vector OLD_FILES+=usr/include/c++/v1/tr1/version OLD_FILES+=usr/include/c++/v1/tr1/wchar.h OLD_FILES+=usr/include/c++/v1/tr1/wctype.h OLD_DIRS+=usr/include/c++/v1/tr1 # 20211027: libdialog shlib bumped to version 10 for dialog 1.3 OLD_LIBS+=usr/lib/libdialog.so.9 OLD_LIBS+=usr/lib/libdpv.so.2 # 20211026: retire obsolete iscsi initiator OLD_FILES+=sbin/iscontrol OLD_FILES+=usr/share/man/man4/iscsi_initiator.4.gz OLD_FILES+=usr/share/man/man8/iscontrol.8.gz # 20211022 OLD_FILES+=etc/rc.d/sppp OLD_FILES+=rescue/spppcontrol OLD_FILES+=sbin/spppcontrol .if ${TARGET_ARCH} == "i386" OLD_FILES+=usr/include/machine/cserial.h .endif OLD_FILES+=usr/include/net/if_sppp.h OLD_FILES+=usr/include/netgraph/ng_sppp.h OLD_FILES+=usr/share/man/man4/ng_sppp.4.gz OLD_FILES+=usr/share/man/man4/sppp.4.gz OLD_FILES+=usr/share/man/man8/spppcontrol.8.gz # 20211004: Removed sparc64 tests for lastcomm/sa OLD_FILES+=usr/tests/usr.bin/lastcomm/v1-sparc64-acct.in OLD_FILES+=usr/tests/usr.bin/lastcomm/v1-sparc64.out OLD_FILES+=usr/tests/usr.bin/lastcomm/v2-sparc64-acct.in OLD_FILES+=usr/tests/usr.bin/lastcomm/v2-sparc64.out OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-sav.in OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-sav.out OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-u.out OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-usr.in OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-usr.out OLD_FILES+=usr/tests/usr.sbin/sa/v2-sparc64-sav.in OLD_FILES+=usr/tests/usr.sbin/sa/v2-sparc64-u.out OLD_FILES+=usr/tests/usr.sbin/sa/v2-sparc64-usr.in # 20210929: OLD_FILES+=usr/sbin/hcseriald OLD_FILES+=usr/share/man/man8/hcseriald.8.gz # 20210929: Remove ng_h4 OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_h4.h OLD_FILES+=usr/share/man/man4/ng_h4.4.gz # 20210923: rename boot(9) to kern_reboot(9) OLD_FILES+=usr/share/man/man9/boot.9.gz # 20210921: remove cloudabi OLD_FILES+=usr/share/man/man4/cloudabi.4.gz OLD_FILES+=usr/share/man/man4/cloudabi32.4.gz OLD_FILES+=usr/share/man/man4/cloudabi64.4.gz # 20210906: stop installing {llvm,clang,lldb}-tblgen OLD_FILES+=usr/bin/llvm-tblgen OLD_FILES+=usr/bin/clang-tblgen OLD_FILES+=usr/bin/lldb-tblgen OLD_FILES+=usr/share/man/man1/llvm-tblgen.1.gz # 20210810: remove Pentium-related man pages and references OLD_FILES+=usr/share/man/man3/pmc.p4.3.gz OLD_FILES+=usr/share/man/man3/pmc.p5.3.gz OLD_FILES+=usr/share/man/man3/pmc.p6.3.gz # 20210805: C.UTF-8 installed to the wrong location OLD_FILES+=usr/share/C.UTF-8.LC_CTYPE # 20210619: new clang import which bumps version from 12.0.0 to 12.0.1 OLD_FILES+=usr/lib/clang/12.0.0/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/12.0.0/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/12.0.0/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/12.0.0/include/cuda_wrappers OLD_FILES+=usr/lib/clang/12.0.0/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/12.0.0/include/fuzzer OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/complex_cmath.h OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/12.0.0/include/openmp_wrappers OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/12.0.0/include/ppc_wrappers OLD_FILES+=usr/lib/clang/12.0.0/include/profile/InstrProfData.inc OLD_DIRS+=usr/lib/clang/12.0.0/include/profile OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/12.0.0/include/sanitizer OLD_FILES+=usr/lib/clang/12.0.0/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/12.0.0/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/12.0.0/include/xray OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_hip_cmath.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/12.0.0/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/12.0.0/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/12.0.0/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/12.0.0/include/adxintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/altivec.h OLD_FILES+=usr/lib/clang/12.0.0/include/ammintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/amxintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/arm64intr.h OLD_FILES+=usr/lib/clang/12.0.0/include/arm_acle.h OLD_FILES+=usr/lib/clang/12.0.0/include/arm_bf16.h OLD_FILES+=usr/lib/clang/12.0.0/include/arm_cde.h OLD_FILES+=usr/lib/clang/12.0.0/include/arm_cmse.h OLD_FILES+=usr/lib/clang/12.0.0/include/arm_fp16.h OLD_FILES+=usr/lib/clang/12.0.0/include/arm_mve.h OLD_FILES+=usr/lib/clang/12.0.0/include/arm_neon.h OLD_FILES+=usr/lib/clang/12.0.0/include/arm_sve.h OLD_FILES+=usr/lib/clang/12.0.0/include/armintr.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx2intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avxintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/avxvnniintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/bmiintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/cet.h OLD_FILES+=usr/lib/clang/12.0.0/include/cetintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/clwbintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/clzerointrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/cpuid.h OLD_FILES+=usr/lib/clang/12.0.0/include/emmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/f16cintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/float.h OLD_FILES+=usr/lib/clang/12.0.0/include/fma4intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/fmaintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/gfniintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/hresetintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/htmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/ia32intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/immintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/inttypes.h OLD_FILES+=usr/lib/clang/12.0.0/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/iso646.h OLD_FILES+=usr/lib/clang/12.0.0/include/keylockerintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/limits.h OLD_FILES+=usr/lib/clang/12.0.0/include/lwpintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/mm3dnow.h OLD_FILES+=usr/lib/clang/12.0.0/include/mm_malloc.h OLD_FILES+=usr/lib/clang/12.0.0/include/mmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/module.modulemap OLD_FILES+=usr/lib/clang/12.0.0/include/movdirintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/msa.h OLD_FILES+=usr/lib/clang/12.0.0/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/nmmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/omp-tools.h OLD_FILES+=usr/lib/clang/12.0.0/include/omp.h OLD_FILES+=usr/lib/clang/12.0.0/include/ompt.h OLD_FILES+=usr/lib/clang/12.0.0/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/12.0.0/include/opencl-c.h OLD_FILES+=usr/lib/clang/12.0.0/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/pkuintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/pmmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/popcntintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/rtmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/s390intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/serializeintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/sgxintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/shaintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/smmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/stdalign.h OLD_FILES+=usr/lib/clang/12.0.0/include/stdarg.h OLD_FILES+=usr/lib/clang/12.0.0/include/stdatomic.h OLD_FILES+=usr/lib/clang/12.0.0/include/stdbool.h OLD_FILES+=usr/lib/clang/12.0.0/include/stddef.h OLD_FILES+=usr/lib/clang/12.0.0/include/stdint.h OLD_FILES+=usr/lib/clang/12.0.0/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/12.0.0/include/tbmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/tgmath.h OLD_FILES+=usr/lib/clang/12.0.0/include/tmmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/uintrintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/unwind.h OLD_FILES+=usr/lib/clang/12.0.0/include/vadefs.h OLD_FILES+=usr/lib/clang/12.0.0/include/vaesintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/varargs.h OLD_FILES+=usr/lib/clang/12.0.0/include/vecintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/12.0.0/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/wmmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/x86gprintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/x86intrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/xmmintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/xopintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/12.0.0/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/12.0.0/include OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/12.0.0/lib/freebsd OLD_DIRS+=usr/lib/clang/12.0.0/lib OLD_DIRS+=usr/lib/clang/12.0.0 # 20210616: Remove crypto_cursor_seg{base,len} OLD_FILES+=usr/share/man/man9/crypto_cursor_segbase.9.gz OLD_FILES+=usr/share/man/man9/crypto_cursor_seglen.9.gz # 20210618: rename of usr/share/certs/blacklisted OLD_FILES+=usr/share/certs/blacklisted/AddTrust_External_Root.pem OLD_FILES+=usr/share/certs/blacklisted/AddTrust_Low-Value_Services_Root.pem OLD_FILES+=usr/share/certs/blacklisted/Camerfirma_Chambers_of_Commerce_Root.pem OLD_FILES+=usr/share/certs/blacklisted/Camerfirma_Global_Chambersign_Root.pem OLD_FILES+=usr/share/certs/blacklisted/Certum_Root_CA.pem OLD_FILES+=usr/share/certs/blacklisted/Chambers_of_Commerce_Root_-_2008.pem OLD_FILES+=usr/share/certs/blacklisted/D-TRUST_Root_CA_3_2013.pem OLD_FILES+=usr/share/certs/blacklisted/EC-ACC.pem OLD_FILES+=usr/share/certs/blacklisted/EE_Certification_Centre_Root_CA.pem OLD_FILES+=usr/share/certs/blacklisted/GeoTrust_Global_CA.pem OLD_FILES+=usr/share/certs/blacklisted/GeoTrust_Primary_Certification_Authority_-_G2.pem OLD_FILES+=usr/share/certs/blacklisted/GeoTrust_Primary_Certification_Authority_-_G3.pem OLD_FILES+=usr/share/certs/blacklisted/GeoTrust_Primary_Certification_Authority.pem OLD_FILES+=usr/share/certs/blacklisted/GeoTrust_Universal_CA_2.pem OLD_FILES+=usr/share/certs/blacklisted/GeoTrust_Universal_CA.pem OLD_FILES+=usr/share/certs/blacklisted/Global_Chambersign_Root_-_2008.pem OLD_FILES+=usr/share/certs/blacklisted/LuxTrust_Global_Root_2.pem OLD_FILES+=usr/share/certs/blacklisted/OISTE_WISeKey_Global_Root_GA_CA.pem OLD_FILES+=usr/share/certs/blacklisted/QuoVadis_Root_CA.pem OLD_FILES+=usr/share/certs/blacklisted/Sonera_Class_2_Root_CA.pem OLD_FILES+=usr/share/certs/blacklisted/Staat_der_Nederlanden_Root_CA_-_G2.pem OLD_FILES+=usr/share/certs/blacklisted/Staat_der_Nederlanden_Root_CA_-_G3.pem OLD_FILES+=usr/share/certs/blacklisted/SwissSign_Platinum_CA_-_G2.pem OLD_FILES+=usr/share/certs/blacklisted/Symantec_Class_1_Public_Primary_Certification_Authority_-_G4.pem OLD_FILES+=usr/share/certs/blacklisted/Symantec_Class_1_Public_Primary_Certification_Authority_-_G6.pem OLD_FILES+=usr/share/certs/blacklisted/Symantec_Class_2_Public_Primary_Certification_Authority_-_G4.pem OLD_FILES+=usr/share/certs/blacklisted/Symantec_Class_2_Public_Primary_Certification_Authority_-_G6.pem OLD_FILES+=usr/share/certs/blacklisted/Taiwan_GRCA.pem OLD_FILES+=usr/share/certs/blacklisted/thawte_Primary_Root_CA_-_G2.pem OLD_FILES+=usr/share/certs/blacklisted/thawte_Primary_Root_CA_-_G3.pem OLD_FILES+=usr/share/certs/blacklisted/thawte_Primary_Root_CA.pem OLD_FILES+=usr/share/certs/blacklisted/Trustis_FPS_Root_CA.pem OLD_FILES+=usr/share/certs/blacklisted/Verisign_Class_1_Public_Primary_Certification_Authority_-_G3.pem OLD_FILES+=usr/share/certs/blacklisted/Verisign_Class_2_Public_Primary_Certification_Authority_-_G3.pem OLD_FILES+=usr/share/certs/blacklisted/Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.pem OLD_FILES+=usr/share/certs/blacklisted/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G4.pem OLD_FILES+=usr/share/certs/blacklisted/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5.pem OLD_FILES+=usr/share/certs/blacklisted/VeriSign_Universal_Root_Certification_Authority.pem OLD_DIRS+=usr/share/certs/blacklisted # 20210613: new clang import which bumps version from 11.0.1 to 12.0.0 OLD_FILES+=usr/lib/clang/11.0.1/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/11.0.1/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/11.0.1/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/11.0.1/include/cuda_wrappers OLD_FILES+=usr/lib/clang/11.0.1/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/11.0.1/include/fuzzer OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/11.0.1/include/openmp_wrappers OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/11.0.1/include/ppc_wrappers OLD_FILES+=usr/lib/clang/11.0.1/include/profile/InstrProfData.inc OLD_DIRS+=usr/lib/clang/11.0.1/include/profile OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/11.0.1/include/sanitizer OLD_FILES+=usr/lib/clang/11.0.1/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/11.0.1/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/11.0.1/include/xray OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/11.0.1/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/11.0.1/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/11.0.1/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/11.0.1/include/adxintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/altivec.h OLD_FILES+=usr/lib/clang/11.0.1/include/ammintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/amxintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/arm64intr.h OLD_FILES+=usr/lib/clang/11.0.1/include/arm_acle.h OLD_FILES+=usr/lib/clang/11.0.1/include/arm_bf16.h OLD_FILES+=usr/lib/clang/11.0.1/include/arm_cde.h OLD_FILES+=usr/lib/clang/11.0.1/include/arm_cmse.h OLD_FILES+=usr/lib/clang/11.0.1/include/arm_fp16.h OLD_FILES+=usr/lib/clang/11.0.1/include/arm_mve.h OLD_FILES+=usr/lib/clang/11.0.1/include/arm_neon.h OLD_FILES+=usr/lib/clang/11.0.1/include/arm_sve.h OLD_FILES+=usr/lib/clang/11.0.1/include/armintr.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx2intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/avxintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/bmiintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/cet.h OLD_FILES+=usr/lib/clang/11.0.1/include/cetintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/clwbintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/clzerointrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/cpuid.h OLD_FILES+=usr/lib/clang/11.0.1/include/emmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/f16cintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/float.h OLD_FILES+=usr/lib/clang/11.0.1/include/fma4intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/fmaintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/gfniintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/htmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/ia32intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/immintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/inttypes.h OLD_FILES+=usr/lib/clang/11.0.1/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/iso646.h OLD_FILES+=usr/lib/clang/11.0.1/include/limits.h OLD_FILES+=usr/lib/clang/11.0.1/include/lwpintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/mm3dnow.h OLD_FILES+=usr/lib/clang/11.0.1/include/mm_malloc.h OLD_FILES+=usr/lib/clang/11.0.1/include/mmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/module.modulemap OLD_FILES+=usr/lib/clang/11.0.1/include/movdirintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/msa.h OLD_FILES+=usr/lib/clang/11.0.1/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/nmmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/omp-tools.h OLD_FILES+=usr/lib/clang/11.0.1/include/omp.h OLD_FILES+=usr/lib/clang/11.0.1/include/ompt.h OLD_FILES+=usr/lib/clang/11.0.1/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/11.0.1/include/opencl-c.h OLD_FILES+=usr/lib/clang/11.0.1/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/pkuintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/pmmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/popcntintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/rtmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/s390intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/serializeintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/sgxintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/shaintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/smmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/stdalign.h OLD_FILES+=usr/lib/clang/11.0.1/include/stdarg.h OLD_FILES+=usr/lib/clang/11.0.1/include/stdatomic.h OLD_FILES+=usr/lib/clang/11.0.1/include/stdbool.h OLD_FILES+=usr/lib/clang/11.0.1/include/stddef.h OLD_FILES+=usr/lib/clang/11.0.1/include/stdint.h OLD_FILES+=usr/lib/clang/11.0.1/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/11.0.1/include/tbmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/tgmath.h OLD_FILES+=usr/lib/clang/11.0.1/include/tmmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/unwind.h OLD_FILES+=usr/lib/clang/11.0.1/include/vadefs.h OLD_FILES+=usr/lib/clang/11.0.1/include/vaesintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/varargs.h OLD_FILES+=usr/lib/clang/11.0.1/include/vecintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/11.0.1/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/wmmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/x86intrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/xmmintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/xopintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/11.0.1/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/11.0.1/include OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/11.0.1/lib/freebsd OLD_DIRS+=usr/lib/clang/11.0.1/lib OLD_DIRS+=usr/lib/clang/11.0.1 # 20210613: Rename OpenZFS manual pages OLD_FILES+=usr/share/man/man5/spl-module-parameters.5.gz OLD_FILES+=usr/share/man/man5/zfs-events.5.gz OLD_FILES+=usr/share/man/man5/zfs-module-parameters.5.gz OLD_FILES+=usr/share/man/man8/zfsconcepts.8.gz OLD_FILES+=usr/share/man/man8/zfsprops.8.gz OLD_FILES+=usr/share/man/man5/zpool-features.5.gz OLD_FILES+=usr/share/man/man8/zpoolconcepts.8.gz OLD_FILES+=usr/share/man/man8/zpoolprops.8.gz # 20210611: Remove svn and svnlite OLD_FILES+=usr/bin/svn OLD_FILES+=usr/bin/svnadmin OLD_FILES+=usr/bin/svnbench OLD_FILES+=usr/bin/svndumpfilter OLD_FILES+=usr/bin/svnfsfs OLD_FILES+=usr/bin/svnlite OLD_FILES+=usr/bin/svnliteadmin OLD_FILES+=usr/bin/svnlitebench OLD_FILES+=usr/bin/svnlitedumpfilter OLD_FILES+=usr/bin/svnlitefsfs OLD_FILES+=usr/bin/svnlitelook OLD_FILES+=usr/bin/svnlitemucc OLD_FILES+=usr/bin/svnliterdump OLD_FILES+=usr/bin/svnliteserve OLD_FILES+=usr/bin/svnlitesync OLD_FILES+=usr/bin/svnliteversion OLD_FILES+=usr/bin/svnlook OLD_FILES+=usr/bin/svnmucc OLD_FILES+=usr/bin/svnrdump OLD_FILES+=usr/bin/svnserve OLD_FILES+=usr/bin/svnsync OLD_FILES+=usr/bin/svnversion OLD_FILES+=usr/share/man/man1/svnlite.1.gz # 20210607: remove ancontrol(8) related programs OLD_FILES+=usr/sbin/ancontrol OLD_FILES+=usr/share/man/man8/ancontrol.8.gz # 20210607: remove an(4) OLD_FILES+=usr/include/dev/an/if_aironet_ieee.h OLD_FILES+=usr/include/dev/an/if_anreg.h OLD_FILES+=usr/share/man/man4/an.4.gz # 20210426: remove unused libexec/rc.d/addswap OLD_FILES+=etc/rc.d/addswap # 20210413: Remove pfctlinput2 OLD_FILES+=usr/share/man/man9/pfctlinput2.9.gz # 20210412: Remove kernel asymmetric crypto OLD_FILES+=usr/share/man/man9/crypto_asym.9.gz OLD_FILES+=usr/share/man/man9/crypto_kdispatch.9.gz OLD_FILES+=usr/share/man/man9/crypto_kdone.9.gz OLD_FILES+=usr/share/man/man9/crypto_kregister.9.gz OLD_FILES+=usr/share/man/man9/CRYPTODEV_KPROCESS.9.gz # 20210410: remove unused libexec/rc.d/archdep OLD_FILES+=etc/rc.d/archdep # 20210408: remove tcp_hostcache.h OLD_FILES+=usr/include/netinet/tcp_hostcache.h # 20210403: remove kgmon(8) OLD_FILES+=usr/sbin/kgmon OLD_FILES+=usr/share/man/man8/kgmon.8.gz # 20210401: remove bt(4) man page OLD_FILES+=usr/share/man/man4/bt.4.gz # 20210322: retire mn(4) sync serial driver OLD_FILES+=usr/share/man/man4/if_mn.4.gz OLD_FILES+=usr/share/man/man4/mn.4.gz # 20210318: remove the terminfo database OLD_FILES+=usr/share/terminfo/1/1178 OLD_FILES+=usr/share/terminfo/1/1730-lm OLD_DIRS+=usr/share/terminfo/1 OLD_FILES+=usr/share/terminfo/2/2621 OLD_FILES+=usr/share/terminfo/2/2621-wl OLD_FILES+=usr/share/terminfo/2/2621A OLD_FILES+=usr/share/terminfo/2/2621a OLD_DIRS+=usr/share/terminfo/2/ OLD_FILES+=usr/share/terminfo/3/386at OLD_FILES+=usr/share/terminfo/3/3b1 OLD_DIRS+=usr/share/terminfo/3/ OLD_FILES+=usr/share/terminfo/4/4025ex OLD_FILES+=usr/share/terminfo/4/4027ex OLD_FILES+=usr/share/terminfo/4/4410-w OLD_DIRS+=usr/share/terminfo/4/ OLD_FILES+=usr/share/terminfo/5/5051 OLD_FILES+=usr/share/terminfo/5/5410-w OLD_FILES+=usr/share/terminfo/5/5620 OLD_FILES+=usr/share/terminfo/5/5630-24 OLD_FILES+=usr/share/terminfo/5/5630DMD-24 OLD_DIRS+=usr/share/terminfo/5/ OLD_FILES+=usr/share/terminfo/6/6053 OLD_FILES+=usr/share/terminfo/6/6053-dg OLD_FILES+=usr/share/terminfo/6/605x OLD_FILES+=usr/share/terminfo/6/605x-dg OLD_FILES+=usr/share/terminfo/6/630-lm OLD_FILES+=usr/share/terminfo/6/630MTG-24 OLD_DIRS+=usr/share/terminfo/6/ OLD_FILES+=usr/share/terminfo/7/730MTG-24 OLD_FILES+=usr/share/terminfo/7/730MTG-41 OLD_FILES+=usr/share/terminfo/7/730MTG-41r OLD_FILES+=usr/share/terminfo/7/730MTGr OLD_FILES+=usr/share/terminfo/7/730MTGr-24 OLD_DIRS+=usr/share/terminfo/7/ OLD_FILES+=usr/share/terminfo/8/8510 OLD_DIRS+=usr/share/terminfo/8/ OLD_FILES+=usr/share/terminfo/9/955-hb OLD_FILES+=usr/share/terminfo/9/955-w OLD_FILES+=usr/share/terminfo/9/9term OLD_DIRS+=usr/share/terminfo/9/ OLD_FILES+=usr/share/terminfo/A/Apple_Terminal OLD_DIRS+=usr/share/terminfo/A/ OLD_FILES+=usr/share/terminfo/E/Eterm OLD_FILES+=usr/share/terminfo/E/Eterm-256color OLD_FILES+=usr/share/terminfo/E/Eterm-88color OLD_FILES+=usr/share/terminfo/E/Eterm-color OLD_DIRS+=usr/share/terminfo/E/ OLD_FILES+=usr/share/terminfo/L/LFT-PC850 OLD_DIRS+=usr/share/terminfo/L/ OLD_FILES+=usr/share/terminfo/M/MtxOrb OLD_FILES+=usr/share/terminfo/M/MtxOrb162 OLD_FILES+=usr/share/terminfo/M/MtxOrb204 OLD_DIRS+=usr/share/terminfo/M/ OLD_FILES+=usr/share/terminfo/N/NCR260VT300WPP OLD_FILES+=usr/share/terminfo/N/NCRVT100WPP OLD_DIRS+=usr/share/terminfo/N/ OLD_FILES+=usr/share/terminfo/P/P12 OLD_FILES+=usr/share/terminfo/P/P12-M OLD_FILES+=usr/share/terminfo/P/P12-M-W OLD_FILES+=usr/share/terminfo/P/P12-W OLD_FILES+=usr/share/terminfo/P/P14 OLD_FILES+=usr/share/terminfo/P/P14-M OLD_FILES+=usr/share/terminfo/P/P14-M-W OLD_FILES+=usr/share/terminfo/P/P14-W OLD_FILES+=usr/share/terminfo/P/P4 OLD_FILES+=usr/share/terminfo/P/P5 OLD_FILES+=usr/share/terminfo/P/P7 OLD_FILES+=usr/share/terminfo/P/P8 OLD_FILES+=usr/share/terminfo/P/P8-W OLD_FILES+=usr/share/terminfo/P/P9 OLD_FILES+=usr/share/terminfo/P/P9-8 OLD_FILES+=usr/share/terminfo/P/P9-8-W OLD_FILES+=usr/share/terminfo/P/P9-W OLD_DIRS+=usr/share/terminfo/P/ OLD_FILES+=usr/share/terminfo/Q/Q306-8-pc OLD_FILES+=usr/share/terminfo/Q/Q310-vip-H OLD_FILES+=usr/share/terminfo/Q/Q310-vip-H-am OLD_FILES+=usr/share/terminfo/Q/Q310-vip-Hw OLD_FILES+=usr/share/terminfo/Q/Q310-vip-w OLD_FILES+=usr/share/terminfo/Q/Q310-vip-w-am OLD_DIRS+=usr/share/terminfo/Q/ OLD_FILES+=usr/share/terminfo/X/X-hpterm OLD_DIRS+=usr/share/terminfo/X/ OLD_FILES+=usr/share/terminfo/a/a210 OLD_FILES+=usr/share/terminfo/a/a80 OLD_FILES+=usr/share/terminfo/a/a980 OLD_FILES+=usr/share/terminfo/a/aa4080 OLD_FILES+=usr/share/terminfo/a/aaa OLD_FILES+=usr/share/terminfo/a/aaa+dec OLD_FILES+=usr/share/terminfo/a/aaa+rv OLD_FILES+=usr/share/terminfo/a/aaa+unk OLD_FILES+=usr/share/terminfo/a/aaa-18 OLD_FILES+=usr/share/terminfo/a/aaa-18-rv OLD_FILES+=usr/share/terminfo/a/aaa-20 OLD_FILES+=usr/share/terminfo/a/aaa-22 OLD_FILES+=usr/share/terminfo/a/aaa-24 OLD_FILES+=usr/share/terminfo/a/aaa-24-rv OLD_FILES+=usr/share/terminfo/a/aaa-26 OLD_FILES+=usr/share/terminfo/a/aaa-28 OLD_FILES+=usr/share/terminfo/a/aaa-30 OLD_FILES+=usr/share/terminfo/a/aaa-30-ctxt OLD_FILES+=usr/share/terminfo/a/aaa-30-rv OLD_FILES+=usr/share/terminfo/a/aaa-30-rv-ctxt OLD_FILES+=usr/share/terminfo/a/aaa-30-s OLD_FILES+=usr/share/terminfo/a/aaa-30-s-ctxt OLD_FILES+=usr/share/terminfo/a/aaa-30-s-rv OLD_FILES+=usr/share/terminfo/a/aaa-30-s-rv-ct OLD_FILES+=usr/share/terminfo/a/aaa-36 OLD_FILES+=usr/share/terminfo/a/aaa-36-rv OLD_FILES+=usr/share/terminfo/a/aaa-40 OLD_FILES+=usr/share/terminfo/a/aaa-40-rv OLD_FILES+=usr/share/terminfo/a/aaa-48 OLD_FILES+=usr/share/terminfo/a/aaa-48-rv OLD_FILES+=usr/share/terminfo/a/aaa-60 OLD_FILES+=usr/share/terminfo/a/aaa-60-dec-rv OLD_FILES+=usr/share/terminfo/a/aaa-60-rv OLD_FILES+=usr/share/terminfo/a/aaa-60-s OLD_FILES+=usr/share/terminfo/a/aaa-60-s-rv OLD_FILES+=usr/share/terminfo/a/aaa-ctxt OLD_FILES+=usr/share/terminfo/a/aaa-db OLD_FILES+=usr/share/terminfo/a/aaa-rv OLD_FILES+=usr/share/terminfo/a/aaa-rv-ctxt OLD_FILES+=usr/share/terminfo/a/aaa-rv-unk OLD_FILES+=usr/share/terminfo/a/aaa-s OLD_FILES+=usr/share/terminfo/a/aaa-s-ctxt OLD_FILES+=usr/share/terminfo/a/aaa-s-rv OLD_FILES+=usr/share/terminfo/a/aaa-s-rv-ctxt OLD_FILES+=usr/share/terminfo/a/aaa-unk OLD_FILES+=usr/share/terminfo/a/aas1901 OLD_FILES+=usr/share/terminfo/a/abm80 OLD_FILES+=usr/share/terminfo/a/abm85 OLD_FILES+=usr/share/terminfo/a/abm85e OLD_FILES+=usr/share/terminfo/a/abm85h OLD_FILES+=usr/share/terminfo/a/abm85h-old OLD_FILES+=usr/share/terminfo/a/absolute OLD_FILES+=usr/share/terminfo/a/act4 OLD_FILES+=usr/share/terminfo/a/act5 OLD_FILES+=usr/share/terminfo/a/addrinfo OLD_FILES+=usr/share/terminfo/a/adds200 OLD_FILES+=usr/share/terminfo/a/adds980 OLD_FILES+=usr/share/terminfo/a/addsviewpoint OLD_FILES+=usr/share/terminfo/a/addsvp60 OLD_FILES+=usr/share/terminfo/a/adm+sgr OLD_FILES+=usr/share/terminfo/a/adm1 OLD_FILES+=usr/share/terminfo/a/adm11 OLD_FILES+=usr/share/terminfo/a/adm1178 OLD_FILES+=usr/share/terminfo/a/adm12 OLD_FILES+=usr/share/terminfo/a/adm1a OLD_FILES+=usr/share/terminfo/a/adm2 OLD_FILES+=usr/share/terminfo/a/adm20 OLD_FILES+=usr/share/terminfo/a/adm21 OLD_FILES+=usr/share/terminfo/a/adm22 OLD_FILES+=usr/share/terminfo/a/adm3 OLD_FILES+=usr/share/terminfo/a/adm31 OLD_FILES+=usr/share/terminfo/a/adm31-old OLD_FILES+=usr/share/terminfo/a/adm36 OLD_FILES+=usr/share/terminfo/a/adm3a OLD_FILES+=usr/share/terminfo/a/adm3a+ OLD_FILES+=usr/share/terminfo/a/adm42 OLD_FILES+=usr/share/terminfo/a/adm42-ns OLD_FILES+=usr/share/terminfo/a/adm5 OLD_FILES+=usr/share/terminfo/a/aepro OLD_FILES+=usr/share/terminfo/a/aixterm OLD_FILES+=usr/share/terminfo/a/aixterm-16color OLD_FILES+=usr/share/terminfo/a/aixterm-m OLD_FILES+=usr/share/terminfo/a/aixterm-m-old OLD_FILES+=usr/share/terminfo/a/aj OLD_FILES+=usr/share/terminfo/a/aj510 OLD_FILES+=usr/share/terminfo/a/aj830 OLD_FILES+=usr/share/terminfo/a/aj832 OLD_FILES+=usr/share/terminfo/a/alacritty OLD_FILES+=usr/share/terminfo/a/alacritty+common OLD_FILES+=usr/share/terminfo/a/alacritty-direct OLD_FILES+=usr/share/terminfo/a/alt2 OLD_FILES+=usr/share/terminfo/a/alt3 OLD_FILES+=usr/share/terminfo/a/alt4 OLD_FILES+=usr/share/terminfo/a/alt5 OLD_FILES+=usr/share/terminfo/a/alt7 OLD_FILES+=usr/share/terminfo/a/alt7pc OLD_FILES+=usr/share/terminfo/a/alto-h19 OLD_FILES+=usr/share/terminfo/a/alto-heath OLD_FILES+=usr/share/terminfo/a/altoh19 OLD_FILES+=usr/share/terminfo/a/altoheath OLD_FILES+=usr/share/terminfo/a/altos-2 OLD_FILES+=usr/share/terminfo/a/altos-3 OLD_FILES+=usr/share/terminfo/a/altos-4 OLD_FILES+=usr/share/terminfo/a/altos-5 OLD_FILES+=usr/share/terminfo/a/altos2 OLD_FILES+=usr/share/terminfo/a/altos3 OLD_FILES+=usr/share/terminfo/a/altos4 OLD_FILES+=usr/share/terminfo/a/altos5 OLD_FILES+=usr/share/terminfo/a/altos7 OLD_FILES+=usr/share/terminfo/a/altos7pc OLD_FILES+=usr/share/terminfo/a/ambas OLD_FILES+=usr/share/terminfo/a/ambassador OLD_FILES+=usr/share/terminfo/a/amiga OLD_FILES+=usr/share/terminfo/a/amiga-8bit OLD_FILES+=usr/share/terminfo/a/amiga-h OLD_FILES+=usr/share/terminfo/a/amiga-vnc OLD_FILES+=usr/share/terminfo/a/amp219 OLD_FILES+=usr/share/terminfo/a/amp219w OLD_FILES+=usr/share/terminfo/a/ampex-219 OLD_FILES+=usr/share/terminfo/a/ampex-219w OLD_FILES+=usr/share/terminfo/a/ampex-232 OLD_FILES+=usr/share/terminfo/a/ampex175 OLD_FILES+=usr/share/terminfo/a/ampex175-b OLD_FILES+=usr/share/terminfo/a/ampex210 OLD_FILES+=usr/share/terminfo/a/ampex219 OLD_FILES+=usr/share/terminfo/a/ampex219w OLD_FILES+=usr/share/terminfo/a/ampex232 OLD_FILES+=usr/share/terminfo/a/ampex232w OLD_FILES+=usr/share/terminfo/a/ampex80 OLD_FILES+=usr/share/terminfo/a/annarbor4080 OLD_FILES+=usr/share/terminfo/a/ansi OLD_FILES+=usr/share/terminfo/a/ansi+arrows OLD_FILES+=usr/share/terminfo/a/ansi+csr OLD_FILES+=usr/share/terminfo/a/ansi+cup OLD_FILES+=usr/share/terminfo/a/ansi+enq OLD_FILES+=usr/share/terminfo/a/ansi+erase OLD_FILES+=usr/share/terminfo/a/ansi+idc OLD_FILES+=usr/share/terminfo/a/ansi+idc1 OLD_FILES+=usr/share/terminfo/a/ansi+idl OLD_FILES+=usr/share/terminfo/a/ansi+idl1 OLD_FILES+=usr/share/terminfo/a/ansi+inittabs OLD_FILES+=usr/share/terminfo/a/ansi+local OLD_FILES+=usr/share/terminfo/a/ansi+local1 OLD_FILES+=usr/share/terminfo/a/ansi+pp OLD_FILES+=usr/share/terminfo/a/ansi+rca OLD_FILES+=usr/share/terminfo/a/ansi+rep OLD_FILES+=usr/share/terminfo/a/ansi+sgr OLD_FILES+=usr/share/terminfo/a/ansi+sgrbold OLD_FILES+=usr/share/terminfo/a/ansi+sgrdim OLD_FILES+=usr/share/terminfo/a/ansi+sgrso OLD_FILES+=usr/share/terminfo/a/ansi+sgrul OLD_FILES+=usr/share/terminfo/a/ansi+tabs OLD_FILES+=usr/share/terminfo/a/ansi-color-2-emx OLD_FILES+=usr/share/terminfo/a/ansi-color-3-emx OLD_FILES+=usr/share/terminfo/a/ansi-emx OLD_FILES+=usr/share/terminfo/a/ansi-generic OLD_FILES+=usr/share/terminfo/a/ansi-m OLD_FILES+=usr/share/terminfo/a/ansi-mini OLD_FILES+=usr/share/terminfo/a/ansi-mono OLD_FILES+=usr/share/terminfo/a/ansi-mr OLD_FILES+=usr/share/terminfo/a/ansi-mtabs OLD_FILES+=usr/share/terminfo/a/ansi-nt OLD_FILES+=usr/share/terminfo/a/ansi.sys OLD_FILES+=usr/share/terminfo/a/ansi.sys-old OLD_FILES+=usr/share/terminfo/a/ansi.sysk OLD_FILES+=usr/share/terminfo/a/ansi43m OLD_FILES+=usr/share/terminfo/a/ansi77 OLD_FILES+=usr/share/terminfo/a/ansi80x25 OLD_FILES+=usr/share/terminfo/a/ansi80x25-mono OLD_FILES+=usr/share/terminfo/a/ansi80x25-raw OLD_FILES+=usr/share/terminfo/a/ansi80x30 OLD_FILES+=usr/share/terminfo/a/ansi80x30-mono OLD_FILES+=usr/share/terminfo/a/ansi80x43 OLD_FILES+=usr/share/terminfo/a/ansi80x43-mono OLD_FILES+=usr/share/terminfo/a/ansi80x50 OLD_FILES+=usr/share/terminfo/a/ansi80x50-mono OLD_FILES+=usr/share/terminfo/a/ansi80x60 OLD_FILES+=usr/share/terminfo/a/ansi80x60-mono OLD_FILES+=usr/share/terminfo/a/ansil OLD_FILES+=usr/share/terminfo/a/ansil-mono OLD_FILES+=usr/share/terminfo/a/ansis OLD_FILES+=usr/share/terminfo/a/ansis-mono OLD_FILES+=usr/share/terminfo/a/ansisysk OLD_FILES+=usr/share/terminfo/a/ansiterm OLD_FILES+=usr/share/terminfo/a/ansiw OLD_FILES+=usr/share/terminfo/a/ap-vm80 OLD_FILES+=usr/share/terminfo/a/apl OLD_FILES+=usr/share/terminfo/a/apollo OLD_FILES+=usr/share/terminfo/a/apollo_15P OLD_FILES+=usr/share/terminfo/a/apollo_19L OLD_FILES+=usr/share/terminfo/a/apollo_color OLD_FILES+=usr/share/terminfo/a/apple-80 OLD_FILES+=usr/share/terminfo/a/apple-ae OLD_FILES+=usr/share/terminfo/a/apple-soroc OLD_FILES+=usr/share/terminfo/a/apple-uterm OLD_FILES+=usr/share/terminfo/a/apple-uterm-vb OLD_FILES+=usr/share/terminfo/a/apple-videx OLD_FILES+=usr/share/terminfo/a/apple-videx2 OLD_FILES+=usr/share/terminfo/a/apple-videx3 OLD_FILES+=usr/share/terminfo/a/apple-vm80 OLD_FILES+=usr/share/terminfo/a/apple2e OLD_FILES+=usr/share/terminfo/a/apple2e-p OLD_FILES+=usr/share/terminfo/a/apple80p OLD_FILES+=usr/share/terminfo/a/appleII OLD_FILES+=usr/share/terminfo/a/appleIIc OLD_FILES+=usr/share/terminfo/a/appleIIe OLD_FILES+=usr/share/terminfo/a/appleIIgs OLD_FILES+=usr/share/terminfo/a/arm100 OLD_FILES+=usr/share/terminfo/a/arm100-am OLD_FILES+=usr/share/terminfo/a/arm100-w OLD_FILES+=usr/share/terminfo/a/arm100-wam OLD_FILES+=usr/share/terminfo/a/at OLD_FILES+=usr/share/terminfo/a/at-color OLD_FILES+=usr/share/terminfo/a/at-m OLD_FILES+=usr/share/terminfo/a/at386 OLD_FILES+=usr/share/terminfo/a/atari OLD_FILES+=usr/share/terminfo/a/atari-color OLD_FILES+=usr/share/terminfo/a/atari-m OLD_FILES+=usr/share/terminfo/a/atari-old OLD_FILES+=usr/share/terminfo/a/atari_st OLD_FILES+=usr/share/terminfo/a/atari_st-color OLD_FILES+=usr/share/terminfo/a/atarist-m OLD_FILES+=usr/share/terminfo/a/aterm OLD_FILES+=usr/share/terminfo/a/att2300 OLD_FILES+=usr/share/terminfo/a/att2350 OLD_FILES+=usr/share/terminfo/a/att4410 OLD_FILES+=usr/share/terminfo/a/att4410-w OLD_FILES+=usr/share/terminfo/a/att4410v1 OLD_FILES+=usr/share/terminfo/a/att4410v1-w OLD_FILES+=usr/share/terminfo/a/att4415 OLD_FILES+=usr/share/terminfo/a/att4415+nl OLD_FILES+=usr/share/terminfo/a/att4415-nl OLD_FILES+=usr/share/terminfo/a/att4415-rv OLD_FILES+=usr/share/terminfo/a/att4415-rv-nl OLD_FILES+=usr/share/terminfo/a/att4415-w OLD_FILES+=usr/share/terminfo/a/att4415-w-nl OLD_FILES+=usr/share/terminfo/a/att4415-w-rv OLD_FILES+=usr/share/terminfo/a/att4415-w-rv-n OLD_FILES+=usr/share/terminfo/a/att4418 OLD_FILES+=usr/share/terminfo/a/att4418-w OLD_FILES+=usr/share/terminfo/a/att4420 OLD_FILES+=usr/share/terminfo/a/att4424 OLD_FILES+=usr/share/terminfo/a/att4424-1 OLD_FILES+=usr/share/terminfo/a/att4424m OLD_FILES+=usr/share/terminfo/a/att4425 OLD_FILES+=usr/share/terminfo/a/att4425-nl OLD_FILES+=usr/share/terminfo/a/att4425-w OLD_FILES+=usr/share/terminfo/a/att4426 OLD_FILES+=usr/share/terminfo/a/att500 OLD_FILES+=usr/share/terminfo/a/att505 OLD_FILES+=usr/share/terminfo/a/att505-24 OLD_FILES+=usr/share/terminfo/a/att510a OLD_FILES+=usr/share/terminfo/a/att510d OLD_FILES+=usr/share/terminfo/a/att513 OLD_FILES+=usr/share/terminfo/a/att5310 OLD_FILES+=usr/share/terminfo/a/att5320 OLD_FILES+=usr/share/terminfo/a/att5410 OLD_FILES+=usr/share/terminfo/a/att5410-w OLD_FILES+=usr/share/terminfo/a/att5410v1 OLD_FILES+=usr/share/terminfo/a/att5410v1-w OLD_FILES+=usr/share/terminfo/a/att5418 OLD_FILES+=usr/share/terminfo/a/att5418-w OLD_FILES+=usr/share/terminfo/a/att5420 OLD_FILES+=usr/share/terminfo/a/att5420+nl OLD_FILES+=usr/share/terminfo/a/att5420-nl OLD_FILES+=usr/share/terminfo/a/att5420-rv OLD_FILES+=usr/share/terminfo/a/att5420-rv-nl OLD_FILES+=usr/share/terminfo/a/att5420-w OLD_FILES+=usr/share/terminfo/a/att5420-w-nl OLD_FILES+=usr/share/terminfo/a/att5420-w-rv OLD_FILES+=usr/share/terminfo/a/att5420-w-rv-n OLD_FILES+=usr/share/terminfo/a/att5420_2 OLD_FILES+=usr/share/terminfo/a/att5420_2-w OLD_FILES+=usr/share/terminfo/a/att5425 OLD_FILES+=usr/share/terminfo/a/att5425-nl OLD_FILES+=usr/share/terminfo/a/att5425-w OLD_FILES+=usr/share/terminfo/a/att5430 OLD_FILES+=usr/share/terminfo/a/att5620 OLD_FILES+=usr/share/terminfo/a/att5620-1 OLD_FILES+=usr/share/terminfo/a/att5620-24 OLD_FILES+=usr/share/terminfo/a/att5620-34 OLD_FILES+=usr/share/terminfo/a/att5620-s OLD_FILES+=usr/share/terminfo/a/att605 OLD_FILES+=usr/share/terminfo/a/att605-pc OLD_FILES+=usr/share/terminfo/a/att605-w OLD_FILES+=usr/share/terminfo/a/att610 OLD_FILES+=usr/share/terminfo/a/att610+cvis OLD_FILES+=usr/share/terminfo/a/att610+cvis0 OLD_FILES+=usr/share/terminfo/a/att610-103k OLD_FILES+=usr/share/terminfo/a/att610-103k-w OLD_FILES+=usr/share/terminfo/a/att610-w OLD_FILES+=usr/share/terminfo/a/att615 OLD_FILES+=usr/share/terminfo/a/att615-103k OLD_FILES+=usr/share/terminfo/a/att615-103k-w OLD_FILES+=usr/share/terminfo/a/att615-w OLD_FILES+=usr/share/terminfo/a/att620 OLD_FILES+=usr/share/terminfo/a/att620-103k OLD_FILES+=usr/share/terminfo/a/att620-103k-w OLD_FILES+=usr/share/terminfo/a/att620-w OLD_FILES+=usr/share/terminfo/a/att630 OLD_FILES+=usr/share/terminfo/a/att630-24 OLD_FILES+=usr/share/terminfo/a/att6386 OLD_FILES+=usr/share/terminfo/a/att700 OLD_FILES+=usr/share/terminfo/a/att730 OLD_FILES+=usr/share/terminfo/a/att730-24 OLD_FILES+=usr/share/terminfo/a/att730-41 OLD_FILES+=usr/share/terminfo/a/att7300 OLD_FILES+=usr/share/terminfo/a/att730r OLD_FILES+=usr/share/terminfo/a/att730r-24 OLD_FILES+=usr/share/terminfo/a/att730r-41 OLD_FILES+=usr/share/terminfo/a/avatar OLD_FILES+=usr/share/terminfo/a/avatar0 OLD_FILES+=usr/share/terminfo/a/avatar0+ OLD_FILES+=usr/share/terminfo/a/avatar1 OLD_FILES+=usr/share/terminfo/a/avt OLD_FILES+=usr/share/terminfo/a/avt+s OLD_FILES+=usr/share/terminfo/a/avt-ns OLD_FILES+=usr/share/terminfo/a/avt-rv OLD_FILES+=usr/share/terminfo/a/avt-rv-ns OLD_FILES+=usr/share/terminfo/a/avt-rv-s OLD_FILES+=usr/share/terminfo/a/avt-s OLD_FILES+=usr/share/terminfo/a/avt-w OLD_FILES+=usr/share/terminfo/a/avt-w-ns OLD_FILES+=usr/share/terminfo/a/avt-w-rv OLD_FILES+=usr/share/terminfo/a/avt-w-rv-ns OLD_FILES+=usr/share/terminfo/a/avt-w-rv-s OLD_FILES+=usr/share/terminfo/a/avt-w-s OLD_FILES+=usr/share/terminfo/a/aws OLD_FILES+=usr/share/terminfo/a/awsc OLD_DIRS+=usr/share/terminfo/a/ OLD_FILES+=usr/share/terminfo/b/b-128 OLD_FILES+=usr/share/terminfo/b/bantam OLD_FILES+=usr/share/terminfo/b/basic4 OLD_FILES+=usr/share/terminfo/b/basis OLD_FILES+=usr/share/terminfo/b/bct510a OLD_FILES+=usr/share/terminfo/b/bct510d OLD_FILES+=usr/share/terminfo/b/beacon OLD_FILES+=usr/share/terminfo/b/bee OLD_FILES+=usr/share/terminfo/b/beehive OLD_FILES+=usr/share/terminfo/b/beehive3 OLD_FILES+=usr/share/terminfo/b/beehive4 OLD_FILES+=usr/share/terminfo/b/beehiveIIIm OLD_FILES+=usr/share/terminfo/b/beterm OLD_FILES+=usr/share/terminfo/b/bg1.25 OLD_FILES+=usr/share/terminfo/b/bg1.25nv OLD_FILES+=usr/share/terminfo/b/bg1.25rv OLD_FILES+=usr/share/terminfo/b/bg2.0 OLD_FILES+=usr/share/terminfo/b/bg2.0nv OLD_FILES+=usr/share/terminfo/b/bg2.0rv OLD_FILES+=usr/share/terminfo/b/bg3.10 OLD_FILES+=usr/share/terminfo/b/bg3.10nv OLD_FILES+=usr/share/terminfo/b/bg3.10rv OLD_FILES+=usr/share/terminfo/b/bh3m OLD_FILES+=usr/share/terminfo/b/bh4 OLD_FILES+=usr/share/terminfo/b/bitgraph OLD_FILES+=usr/share/terminfo/b/blit OLD_FILES+=usr/share/terminfo/b/bobcat OLD_FILES+=usr/share/terminfo/b/bq300 OLD_FILES+=usr/share/terminfo/b/bq300-8 OLD_FILES+=usr/share/terminfo/b/bq300-8-pc OLD_FILES+=usr/share/terminfo/b/bq300-8-pc-rv OLD_FILES+=usr/share/terminfo/b/bq300-8-pc-w OLD_FILES+=usr/share/terminfo/b/bq300-8-pc-w-rv OLD_FILES+=usr/share/terminfo/b/bq300-8rv OLD_FILES+=usr/share/terminfo/b/bq300-8w OLD_FILES+=usr/share/terminfo/b/bq300-pc OLD_FILES+=usr/share/terminfo/b/bq300-pc-rv OLD_FILES+=usr/share/terminfo/b/bq300-pc-w OLD_FILES+=usr/share/terminfo/b/bq300-pc-w-rv OLD_FILES+=usr/share/terminfo/b/bq300-rv OLD_FILES+=usr/share/terminfo/b/bq300-w OLD_FILES+=usr/share/terminfo/b/bq300-w-8rv OLD_FILES+=usr/share/terminfo/b/bq300-w-rv OLD_FILES+=usr/share/terminfo/b/bsdos-pc OLD_FILES+=usr/share/terminfo/b/bsdos-pc-m OLD_FILES+=usr/share/terminfo/b/bsdos-pc-mono OLD_FILES+=usr/share/terminfo/b/bsdos-pc-nobold OLD_FILES+=usr/share/terminfo/b/bsdos-ppc OLD_FILES+=usr/share/terminfo/b/bsdos-sparc OLD_FILES+=usr/share/terminfo/b/bterm OLD_DIRS+=usr/share/terminfo/b/ OLD_FILES+=usr/share/terminfo/c/c100 OLD_FILES+=usr/share/terminfo/c/c100-1p OLD_FILES+=usr/share/terminfo/c/c100-4p OLD_FILES+=usr/share/terminfo/c/c100-rv OLD_FILES+=usr/share/terminfo/c/c100-rv-4p OLD_FILES+=usr/share/terminfo/c/c104 OLD_FILES+=usr/share/terminfo/c/c108 OLD_FILES+=usr/share/terminfo/c/c108-4p OLD_FILES+=usr/share/terminfo/c/c108-8p OLD_FILES+=usr/share/terminfo/c/c108-rv OLD_FILES+=usr/share/terminfo/c/c108-rv-4p OLD_FILES+=usr/share/terminfo/c/c108-rv-8p OLD_FILES+=usr/share/terminfo/c/c108-w OLD_FILES+=usr/share/terminfo/c/c108-w-8p OLD_FILES+=usr/share/terminfo/c/c300 OLD_FILES+=usr/share/terminfo/c/c301 OLD_FILES+=usr/share/terminfo/c/c321 OLD_FILES+=usr/share/terminfo/c/ca22851 OLD_FILES+=usr/share/terminfo/c/cad68-2 OLD_FILES+=usr/share/terminfo/c/cad68-3 OLD_FILES+=usr/share/terminfo/c/cbblit OLD_FILES+=usr/share/terminfo/c/cbunix OLD_FILES+=usr/share/terminfo/c/cci OLD_FILES+=usr/share/terminfo/c/cci1 OLD_FILES+=usr/share/terminfo/c/cdc456 OLD_FILES+=usr/share/terminfo/c/cdc721 OLD_FILES+=usr/share/terminfo/c/cdc721-esc OLD_FILES+=usr/share/terminfo/c/cdc721ll OLD_FILES+=usr/share/terminfo/c/cdc752 OLD_FILES+=usr/share/terminfo/c/cdc756 OLD_FILES+=usr/share/terminfo/c/cg7900 OLD_FILES+=usr/share/terminfo/c/cgc2 OLD_FILES+=usr/share/terminfo/c/cgc3 OLD_FILES+=usr/share/terminfo/c/chromatics OLD_FILES+=usr/share/terminfo/c/ci8510 OLD_FILES+=usr/share/terminfo/c/cit-80 OLD_FILES+=usr/share/terminfo/c/cit101 OLD_FILES+=usr/share/terminfo/c/cit101e OLD_FILES+=usr/share/terminfo/c/cit101e-132 OLD_FILES+=usr/share/terminfo/c/cit101e-n OLD_FILES+=usr/share/terminfo/c/cit101e-n132 OLD_FILES+=usr/share/terminfo/c/cit101e-rv OLD_FILES+=usr/share/terminfo/c/cit500 OLD_FILES+=usr/share/terminfo/c/cit80 OLD_FILES+=usr/share/terminfo/c/citc OLD_FILES+=usr/share/terminfo/c/citoh OLD_FILES+=usr/share/terminfo/c/citoh-6lpi OLD_FILES+=usr/share/terminfo/c/citoh-8lpi OLD_FILES+=usr/share/terminfo/c/citoh-comp OLD_FILES+=usr/share/terminfo/c/citoh-elite OLD_FILES+=usr/share/terminfo/c/citoh-pica OLD_FILES+=usr/share/terminfo/c/citoh-prop OLD_FILES+=usr/share/terminfo/c/citoh-ps OLD_FILES+=usr/share/terminfo/c/coco3 OLD_FILES+=usr/share/terminfo/c/coherent OLD_FILES+=usr/share/terminfo/c/color_xterm OLD_FILES+=usr/share/terminfo/c/colorscan OLD_FILES+=usr/share/terminfo/c/commodore OLD_FILES+=usr/share/terminfo/c/concept OLD_FILES+=usr/share/terminfo/c/concept-avt OLD_FILES+=usr/share/terminfo/c/concept100 OLD_FILES+=usr/share/terminfo/c/concept100-rv OLD_FILES+=usr/share/terminfo/c/concept108 OLD_FILES+=usr/share/terminfo/c/concept108-4p OLD_FILES+=usr/share/terminfo/c/concept108-8p OLD_FILES+=usr/share/terminfo/c/concept108-w-8 OLD_FILES+=usr/share/terminfo/c/concept108-w8p OLD_FILES+=usr/share/terminfo/c/concept108rv4p OLD_FILES+=usr/share/terminfo/c/cons25 OLD_FILES+=usr/share/terminfo/c/cons25-debian OLD_FILES+=usr/share/terminfo/c/cons25-iso-m OLD_FILES+=usr/share/terminfo/c/cons25-iso8859 OLD_FILES+=usr/share/terminfo/c/cons25-koi8-r OLD_FILES+=usr/share/terminfo/c/cons25-koi8r-m OLD_FILES+=usr/share/terminfo/c/cons25-m OLD_FILES+=usr/share/terminfo/c/cons25l1 OLD_FILES+=usr/share/terminfo/c/cons25l1-m OLD_FILES+=usr/share/terminfo/c/cons25r OLD_FILES+=usr/share/terminfo/c/cons25r-m OLD_FILES+=usr/share/terminfo/c/cons25w OLD_FILES+=usr/share/terminfo/c/cons30 OLD_FILES+=usr/share/terminfo/c/cons30-m OLD_FILES+=usr/share/terminfo/c/cons43 OLD_FILES+=usr/share/terminfo/c/cons43-m OLD_FILES+=usr/share/terminfo/c/cons50 OLD_FILES+=usr/share/terminfo/c/cons50-iso-m OLD_FILES+=usr/share/terminfo/c/cons50-iso8859 OLD_FILES+=usr/share/terminfo/c/cons50-koi8r OLD_FILES+=usr/share/terminfo/c/cons50-koi8r-m OLD_FILES+=usr/share/terminfo/c/cons50-m OLD_FILES+=usr/share/terminfo/c/cons50l1 OLD_FILES+=usr/share/terminfo/c/cons50l1-m OLD_FILES+=usr/share/terminfo/c/cons50r OLD_FILES+=usr/share/terminfo/c/cons50r-m OLD_FILES+=usr/share/terminfo/c/cons60 OLD_FILES+=usr/share/terminfo/c/cons60-iso OLD_FILES+=usr/share/terminfo/c/cons60-iso-m OLD_FILES+=usr/share/terminfo/c/cons60-koi8r OLD_FILES+=usr/share/terminfo/c/cons60-koi8r-m OLD_FILES+=usr/share/terminfo/c/cons60-m OLD_FILES+=usr/share/terminfo/c/cons60l1 OLD_FILES+=usr/share/terminfo/c/cons60l1-m OLD_FILES+=usr/share/terminfo/c/cons60r OLD_FILES+=usr/share/terminfo/c/cons60r-m OLD_FILES+=usr/share/terminfo/c/contel300 OLD_FILES+=usr/share/terminfo/c/contel301 OLD_FILES+=usr/share/terminfo/c/contel320 OLD_FILES+=usr/share/terminfo/c/contel321 OLD_FILES+=usr/share/terminfo/c/cops OLD_FILES+=usr/share/terminfo/c/cops-10 OLD_FILES+=usr/share/terminfo/c/cops10 OLD_FILES+=usr/share/terminfo/c/crt OLD_FILES+=usr/share/terminfo/c/crt-vt220 OLD_FILES+=usr/share/terminfo/c/cs10 OLD_FILES+=usr/share/terminfo/c/cs10-w OLD_FILES+=usr/share/terminfo/c/ct82 OLD_FILES+=usr/share/terminfo/c/ct8500 OLD_FILES+=usr/share/terminfo/c/ctrm OLD_FILES+=usr/share/terminfo/c/cx OLD_FILES+=usr/share/terminfo/c/cx100 OLD_FILES+=usr/share/terminfo/c/cyb110 OLD_FILES+=usr/share/terminfo/c/cyb83 OLD_FILES+=usr/share/terminfo/c/cygwin OLD_FILES+=usr/share/terminfo/c/cygwinB19 OLD_FILES+=usr/share/terminfo/c/cygwinDBG OLD_DIRS+=usr/share/terminfo/c/ OLD_FILES+=usr/share/terminfo/d/d132 OLD_FILES+=usr/share/terminfo/d/d2 OLD_FILES+=usr/share/terminfo/d/d2-dg OLD_FILES+=usr/share/terminfo/d/d200 OLD_FILES+=usr/share/terminfo/d/d200-dg OLD_FILES+=usr/share/terminfo/d/d210 OLD_FILES+=usr/share/terminfo/d/d210-dg OLD_FILES+=usr/share/terminfo/d/d211 OLD_FILES+=usr/share/terminfo/d/d211-7b OLD_FILES+=usr/share/terminfo/d/d211-dg OLD_FILES+=usr/share/terminfo/d/d214 OLD_FILES+=usr/share/terminfo/d/d214-dg OLD_FILES+=usr/share/terminfo/d/d215 OLD_FILES+=usr/share/terminfo/d/d215-7b OLD_FILES+=usr/share/terminfo/d/d215-dg OLD_FILES+=usr/share/terminfo/d/d216+ OLD_FILES+=usr/share/terminfo/d/d216+25 OLD_FILES+=usr/share/terminfo/d/d216+dg OLD_FILES+=usr/share/terminfo/d/d216-dg OLD_FILES+=usr/share/terminfo/d/d216-unix OLD_FILES+=usr/share/terminfo/d/d216-unix-25 OLD_FILES+=usr/share/terminfo/d/d216e+ OLD_FILES+=usr/share/terminfo/d/d216e+dg OLD_FILES+=usr/share/terminfo/d/d216e-dg OLD_FILES+=usr/share/terminfo/d/d216e-unix OLD_FILES+=usr/share/terminfo/d/d217-dg OLD_FILES+=usr/share/terminfo/d/d217-unix OLD_FILES+=usr/share/terminfo/d/d217-unix-25 OLD_FILES+=usr/share/terminfo/d/d220 OLD_FILES+=usr/share/terminfo/d/d220-7b OLD_FILES+=usr/share/terminfo/d/d220-dg OLD_FILES+=usr/share/terminfo/d/d230 OLD_FILES+=usr/share/terminfo/d/d230-dg OLD_FILES+=usr/share/terminfo/d/d230c OLD_FILES+=usr/share/terminfo/d/d230c-dg OLD_FILES+=usr/share/terminfo/d/d400 OLD_FILES+=usr/share/terminfo/d/d400-dg OLD_FILES+=usr/share/terminfo/d/d410 OLD_FILES+=usr/share/terminfo/d/d410-7b OLD_FILES+=usr/share/terminfo/d/d410-7b-w OLD_FILES+=usr/share/terminfo/d/d410-dg OLD_FILES+=usr/share/terminfo/d/d410-w OLD_FILES+=usr/share/terminfo/d/d411 OLD_FILES+=usr/share/terminfo/d/d411-7b OLD_FILES+=usr/share/terminfo/d/d411-7b-w OLD_FILES+=usr/share/terminfo/d/d411-dg OLD_FILES+=usr/share/terminfo/d/d411-w OLD_FILES+=usr/share/terminfo/d/d412+ OLD_FILES+=usr/share/terminfo/d/d412+25 OLD_FILES+=usr/share/terminfo/d/d412+dg OLD_FILES+=usr/share/terminfo/d/d412+s OLD_FILES+=usr/share/terminfo/d/d412+sr OLD_FILES+=usr/share/terminfo/d/d412+w OLD_FILES+=usr/share/terminfo/d/d412-dg OLD_FILES+=usr/share/terminfo/d/d412-unix OLD_FILES+=usr/share/terminfo/d/d412-unix-25 OLD_FILES+=usr/share/terminfo/d/d412-unix-s OLD_FILES+=usr/share/terminfo/d/d412-unix-sr OLD_FILES+=usr/share/terminfo/d/d412-unix-w OLD_FILES+=usr/share/terminfo/d/d413-dg OLD_FILES+=usr/share/terminfo/d/d413-unix OLD_FILES+=usr/share/terminfo/d/d413-unix-25 OLD_FILES+=usr/share/terminfo/d/d413-unix-s OLD_FILES+=usr/share/terminfo/d/d413-unix-sr OLD_FILES+=usr/share/terminfo/d/d413-unix-w OLD_FILES+=usr/share/terminfo/d/d414-unix OLD_FILES+=usr/share/terminfo/d/d414-unix-25 OLD_FILES+=usr/share/terminfo/d/d414-unix-s OLD_FILES+=usr/share/terminfo/d/d414-unix-sr OLD_FILES+=usr/share/terminfo/d/d414-unix-w OLD_FILES+=usr/share/terminfo/d/d430-dg OLD_FILES+=usr/share/terminfo/d/d430-dg-ccc OLD_FILES+=usr/share/terminfo/d/d430-unix OLD_FILES+=usr/share/terminfo/d/d430-unix-25 OLD_FILES+=usr/share/terminfo/d/d430-unix-25-ccc OLD_FILES+=usr/share/terminfo/d/d430-unix-ccc OLD_FILES+=usr/share/terminfo/d/d430-unix-s OLD_FILES+=usr/share/terminfo/d/d430-unix-s-ccc OLD_FILES+=usr/share/terminfo/d/d430-unix-sr OLD_FILES+=usr/share/terminfo/d/d430-unix-sr-ccc OLD_FILES+=usr/share/terminfo/d/d430-unix-w OLD_FILES+=usr/share/terminfo/d/d430-unix-w-ccc OLD_FILES+=usr/share/terminfo/d/d430c-dg OLD_FILES+=usr/share/terminfo/d/d430c-dg-ccc OLD_FILES+=usr/share/terminfo/d/d430c-unix OLD_FILES+=usr/share/terminfo/d/d430c-unix-25 OLD_FILES+=usr/share/terminfo/d/d430c-unix-25-ccc OLD_FILES+=usr/share/terminfo/d/d430c-unix-ccc OLD_FILES+=usr/share/terminfo/d/d430c-unix-s OLD_FILES+=usr/share/terminfo/d/d430c-unix-s-ccc OLD_FILES+=usr/share/terminfo/d/d430c-unix-sr OLD_FILES+=usr/share/terminfo/d/d430c-unix-sr-ccc OLD_FILES+=usr/share/terminfo/d/d430c-unix-w OLD_FILES+=usr/share/terminfo/d/d430c-unix-w-ccc OLD_FILES+=usr/share/terminfo/d/d450 OLD_FILES+=usr/share/terminfo/d/d450-dg OLD_FILES+=usr/share/terminfo/d/d460 OLD_FILES+=usr/share/terminfo/d/d460-7b OLD_FILES+=usr/share/terminfo/d/d460-7b-w OLD_FILES+=usr/share/terminfo/d/d460-dg OLD_FILES+=usr/share/terminfo/d/d460-w OLD_FILES+=usr/share/terminfo/d/d461 OLD_FILES+=usr/share/terminfo/d/d461-7b OLD_FILES+=usr/share/terminfo/d/d461-7b-w OLD_FILES+=usr/share/terminfo/d/d461-dg OLD_FILES+=usr/share/terminfo/d/d461-w OLD_FILES+=usr/share/terminfo/d/d462+ OLD_FILES+=usr/share/terminfo/d/d462+25 OLD_FILES+=usr/share/terminfo/d/d462+dg OLD_FILES+=usr/share/terminfo/d/d462+s OLD_FILES+=usr/share/terminfo/d/d462+sr OLD_FILES+=usr/share/terminfo/d/d462+w OLD_FILES+=usr/share/terminfo/d/d462-dg OLD_FILES+=usr/share/terminfo/d/d462-unix OLD_FILES+=usr/share/terminfo/d/d462-unix-25 OLD_FILES+=usr/share/terminfo/d/d462-unix-s OLD_FILES+=usr/share/terminfo/d/d462-unix-sr OLD_FILES+=usr/share/terminfo/d/d462-unix-w OLD_FILES+=usr/share/terminfo/d/d462e-dg OLD_FILES+=usr/share/terminfo/d/d463-dg OLD_FILES+=usr/share/terminfo/d/d463-unix OLD_FILES+=usr/share/terminfo/d/d463-unix-25 OLD_FILES+=usr/share/terminfo/d/d463-unix-s OLD_FILES+=usr/share/terminfo/d/d463-unix-sr OLD_FILES+=usr/share/terminfo/d/d463-unix-w OLD_FILES+=usr/share/terminfo/d/d464-unix OLD_FILES+=usr/share/terminfo/d/d464-unix-25 OLD_FILES+=usr/share/terminfo/d/d464-unix-s OLD_FILES+=usr/share/terminfo/d/d464-unix-sr OLD_FILES+=usr/share/terminfo/d/d464-unix-w OLD_FILES+=usr/share/terminfo/d/d470 OLD_FILES+=usr/share/terminfo/d/d470-7b OLD_FILES+=usr/share/terminfo/d/d470-dg OLD_FILES+=usr/share/terminfo/d/d470c OLD_FILES+=usr/share/terminfo/d/d470c-7b OLD_FILES+=usr/share/terminfo/d/d470c-dg OLD_FILES+=usr/share/terminfo/d/d555 OLD_FILES+=usr/share/terminfo/d/d555-7b OLD_FILES+=usr/share/terminfo/d/d555-7b-w OLD_FILES+=usr/share/terminfo/d/d555-dg OLD_FILES+=usr/share/terminfo/d/d555-w OLD_FILES+=usr/share/terminfo/d/d577 OLD_FILES+=usr/share/terminfo/d/d577-7b OLD_FILES+=usr/share/terminfo/d/d577-7b-w OLD_FILES+=usr/share/terminfo/d/d577-dg OLD_FILES+=usr/share/terminfo/d/d577-w OLD_FILES+=usr/share/terminfo/d/d578 OLD_FILES+=usr/share/terminfo/d/d578-7b OLD_FILES+=usr/share/terminfo/d/d578-dg OLD_FILES+=usr/share/terminfo/d/d80 OLD_FILES+=usr/share/terminfo/d/d800 OLD_FILES+=usr/share/terminfo/d/darwin OLD_FILES+=usr/share/terminfo/d/darwin-100x37 OLD_FILES+=usr/share/terminfo/d/darwin-100x37-m OLD_FILES+=usr/share/terminfo/d/darwin-112x37 OLD_FILES+=usr/share/terminfo/d/darwin-112x37-m OLD_FILES+=usr/share/terminfo/d/darwin-128x40 OLD_FILES+=usr/share/terminfo/d/darwin-128x40-m OLD_FILES+=usr/share/terminfo/d/darwin-128x48 OLD_FILES+=usr/share/terminfo/d/darwin-128x48-m OLD_FILES+=usr/share/terminfo/d/darwin-144x48 OLD_FILES+=usr/share/terminfo/d/darwin-144x48-m OLD_FILES+=usr/share/terminfo/d/darwin-160x64 OLD_FILES+=usr/share/terminfo/d/darwin-160x64-m OLD_FILES+=usr/share/terminfo/d/darwin-200x64 OLD_FILES+=usr/share/terminfo/d/darwin-200x64-m OLD_FILES+=usr/share/terminfo/d/darwin-200x75 OLD_FILES+=usr/share/terminfo/d/darwin-200x75-m OLD_FILES+=usr/share/terminfo/d/darwin-256x96 OLD_FILES+=usr/share/terminfo/d/darwin-256x96-m OLD_FILES+=usr/share/terminfo/d/darwin-80x25 OLD_FILES+=usr/share/terminfo/d/darwin-80x25-m OLD_FILES+=usr/share/terminfo/d/darwin-80x30 OLD_FILES+=usr/share/terminfo/d/darwin-80x30-m OLD_FILES+=usr/share/terminfo/d/darwin-90x30 OLD_FILES+=usr/share/terminfo/d/darwin-90x30-m OLD_FILES+=usr/share/terminfo/d/darwin-b OLD_FILES+=usr/share/terminfo/d/darwin-f OLD_FILES+=usr/share/terminfo/d/darwin-f2 OLD_FILES+=usr/share/terminfo/d/darwin-m OLD_FILES+=usr/share/terminfo/d/darwin-m-b OLD_FILES+=usr/share/terminfo/d/darwin-m-f OLD_FILES+=usr/share/terminfo/d/darwin-m-f2 OLD_FILES+=usr/share/terminfo/d/datagraphix OLD_FILES+=usr/share/terminfo/d/datamedia2500 OLD_FILES+=usr/share/terminfo/d/datapoint OLD_FILES+=usr/share/terminfo/d/dataspeed40 OLD_FILES+=usr/share/terminfo/d/dd5000 OLD_FILES+=usr/share/terminfo/d/ddr OLD_FILES+=usr/share/terminfo/d/ddr3180 OLD_FILES+=usr/share/terminfo/d/dec+pp OLD_FILES+=usr/share/terminfo/d/dec+sl OLD_FILES+=usr/share/terminfo/d/dec-vt100 OLD_FILES+=usr/share/terminfo/d/dec-vt220 OLD_FILES+=usr/share/terminfo/d/dec-vt330 OLD_FILES+=usr/share/terminfo/d/dec-vt340 OLD_FILES+=usr/share/terminfo/d/dec-vt400 OLD_FILES+=usr/share/terminfo/d/decansi OLD_FILES+=usr/share/terminfo/d/decpro OLD_FILES+=usr/share/terminfo/d/decwriter OLD_FILES+=usr/share/terminfo/d/delta OLD_FILES+=usr/share/terminfo/d/dg+ccc OLD_FILES+=usr/share/terminfo/d/dg+color OLD_FILES+=usr/share/terminfo/d/dg+color8 OLD_FILES+=usr/share/terminfo/d/dg+fixed OLD_FILES+=usr/share/terminfo/d/dg-ansi OLD_FILES+=usr/share/terminfo/d/dg-generic OLD_FILES+=usr/share/terminfo/d/dg100 OLD_FILES+=usr/share/terminfo/d/dg200 OLD_FILES+=usr/share/terminfo/d/dg210 OLD_FILES+=usr/share/terminfo/d/dg211 OLD_FILES+=usr/share/terminfo/d/dg450 OLD_FILES+=usr/share/terminfo/d/dg460-ansi OLD_FILES+=usr/share/terminfo/d/dg6053 OLD_FILES+=usr/share/terminfo/d/dg6053-old OLD_FILES+=usr/share/terminfo/d/dg605x OLD_FILES+=usr/share/terminfo/d/dg6134 OLD_FILES+=usr/share/terminfo/d/dgkeys+11 OLD_FILES+=usr/share/terminfo/d/dgkeys+15 OLD_FILES+=usr/share/terminfo/d/dgkeys+7b OLD_FILES+=usr/share/terminfo/d/dgkeys+8b OLD_FILES+=usr/share/terminfo/d/dgmode+color OLD_FILES+=usr/share/terminfo/d/dgmode+color8 OLD_FILES+=usr/share/terminfo/d/dgunix+ccc OLD_FILES+=usr/share/terminfo/d/dgunix+fixed OLD_FILES+=usr/share/terminfo/d/diablo OLD_FILES+=usr/share/terminfo/d/diablo-lm OLD_FILES+=usr/share/terminfo/d/diablo1620 OLD_FILES+=usr/share/terminfo/d/diablo1620-m8 OLD_FILES+=usr/share/terminfo/d/diablo1640 OLD_FILES+=usr/share/terminfo/d/diablo1640-lm OLD_FILES+=usr/share/terminfo/d/diablo1640-m8 OLD_FILES+=usr/share/terminfo/d/diablo1720 OLD_FILES+=usr/share/terminfo/d/diablo1730 OLD_FILES+=usr/share/terminfo/d/diablo1740 OLD_FILES+=usr/share/terminfo/d/diablo1740-lm OLD_FILES+=usr/share/terminfo/d/diablo450 OLD_FILES+=usr/share/terminfo/d/diablo630 OLD_FILES+=usr/share/terminfo/d/dialogue OLD_FILES+=usr/share/terminfo/d/dialogue80 OLD_FILES+=usr/share/terminfo/d/digilog OLD_FILES+=usr/share/terminfo/d/djgpp OLD_FILES+=usr/share/terminfo/d/djgpp203 OLD_FILES+=usr/share/terminfo/d/djgpp204 OLD_FILES+=usr/share/terminfo/d/dku7003 OLD_FILES+=usr/share/terminfo/d/dku7003-dumb OLD_FILES+=usr/share/terminfo/d/dku7102 OLD_FILES+=usr/share/terminfo/d/dku7102-old OLD_FILES+=usr/share/terminfo/d/dku7102-sna OLD_FILES+=usr/share/terminfo/d/dku7103-sna OLD_FILES+=usr/share/terminfo/d/dku7202 OLD_FILES+=usr/share/terminfo/d/dm1520 OLD_FILES+=usr/share/terminfo/d/dm1521 OLD_FILES+=usr/share/terminfo/d/dm2500 OLD_FILES+=usr/share/terminfo/d/dm3025 OLD_FILES+=usr/share/terminfo/d/dm3045 OLD_FILES+=usr/share/terminfo/d/dm80 OLD_FILES+=usr/share/terminfo/d/dm80w OLD_FILES+=usr/share/terminfo/d/dmchat OLD_FILES+=usr/share/terminfo/d/dmd OLD_FILES+=usr/share/terminfo/d/dmd-24 OLD_FILES+=usr/share/terminfo/d/dmd-34 OLD_FILES+=usr/share/terminfo/d/dmd1 OLD_FILES+=usr/share/terminfo/d/dmdt80 OLD_FILES+=usr/share/terminfo/d/dmdt80w OLD_FILES+=usr/share/terminfo/d/dmterm OLD_FILES+=usr/share/terminfo/d/domterm OLD_FILES+=usr/share/terminfo/d/dp3360 OLD_FILES+=usr/share/terminfo/d/dp8242 OLD_FILES+=usr/share/terminfo/d/ds40 OLD_FILES+=usr/share/terminfo/d/ds40-2 OLD_FILES+=usr/share/terminfo/d/dt-100 OLD_FILES+=usr/share/terminfo/d/dt-100w OLD_FILES+=usr/share/terminfo/d/dt100 OLD_FILES+=usr/share/terminfo/d/dt100w OLD_FILES+=usr/share/terminfo/d/dt110 OLD_FILES+=usr/share/terminfo/d/dt80 OLD_FILES+=usr/share/terminfo/d/dt80-sas OLD_FILES+=usr/share/terminfo/d/dt80w OLD_FILES+=usr/share/terminfo/d/dtc300s OLD_FILES+=usr/share/terminfo/d/dtc382 OLD_FILES+=usr/share/terminfo/d/dtterm OLD_FILES+=usr/share/terminfo/d/dumb OLD_FILES+=usr/share/terminfo/d/dumb-emacs-ansi OLD_FILES+=usr/share/terminfo/d/dvtm OLD_FILES+=usr/share/terminfo/d/dvtm-256color OLD_FILES+=usr/share/terminfo/d/dw OLD_FILES+=usr/share/terminfo/d/dw1 OLD_FILES+=usr/share/terminfo/d/dw2 OLD_FILES+=usr/share/terminfo/d/dw3 OLD_FILES+=usr/share/terminfo/d/dw4 OLD_FILES+=usr/share/terminfo/d/dwk OLD_FILES+=usr/share/terminfo/d/dwk-vt OLD_DIRS+=usr/share/terminfo/d/ OLD_FILES+=usr/share/terminfo/e/ecma+color OLD_FILES+=usr/share/terminfo/e/ecma+index OLD_FILES+=usr/share/terminfo/e/ecma+italics OLD_FILES+=usr/share/terminfo/e/ecma+sgr OLD_FILES+=usr/share/terminfo/e/ecma+strikeout OLD_FILES+=usr/share/terminfo/e/elks OLD_FILES+=usr/share/terminfo/e/elks-ansi OLD_FILES+=usr/share/terminfo/e/elks-glasstty OLD_FILES+=usr/share/terminfo/e/elks-vt52 OLD_FILES+=usr/share/terminfo/e/emots OLD_FILES+=usr/share/terminfo/e/emu OLD_FILES+=usr/share/terminfo/e/emu-220 OLD_FILES+=usr/share/terminfo/e/emx-base OLD_FILES+=usr/share/terminfo/e/env230 OLD_FILES+=usr/share/terminfo/e/envision230 OLD_FILES+=usr/share/terminfo/e/ep40 OLD_FILES+=usr/share/terminfo/e/ep4000 OLD_FILES+=usr/share/terminfo/e/ep4080 OLD_FILES+=usr/share/terminfo/e/ep48 OLD_FILES+=usr/share/terminfo/e/ergo4000 OLD_FILES+=usr/share/terminfo/e/esprit OLD_FILES+=usr/share/terminfo/e/esprit-am OLD_FILES+=usr/share/terminfo/e/eterm OLD_FILES+=usr/share/terminfo/e/eterm-color OLD_FILES+=usr/share/terminfo/e/ex155 OLD_FILES+=usr/share/terminfo/e/excel62 OLD_FILES+=usr/share/terminfo/e/excel62-rv OLD_FILES+=usr/share/terminfo/e/excel62-w OLD_FILES+=usr/share/terminfo/e/excel64 OLD_FILES+=usr/share/terminfo/e/excel64-rv OLD_FILES+=usr/share/terminfo/e/excel64-w OLD_FILES+=usr/share/terminfo/e/exec80 OLD_DIRS+=usr/share/terminfo/e/ OLD_FILES+=usr/share/terminfo/f/f100 OLD_FILES+=usr/share/terminfo/f/f100-rv OLD_FILES+=usr/share/terminfo/f/f110 OLD_FILES+=usr/share/terminfo/f/f110-14 OLD_FILES+=usr/share/terminfo/f/f110-14w OLD_FILES+=usr/share/terminfo/f/f110-w OLD_FILES+=usr/share/terminfo/f/f1720 OLD_FILES+=usr/share/terminfo/f/f1720a OLD_FILES+=usr/share/terminfo/f/f200 OLD_FILES+=usr/share/terminfo/f/f200-w OLD_FILES+=usr/share/terminfo/f/f200vi OLD_FILES+=usr/share/terminfo/f/f200vi-w OLD_FILES+=usr/share/terminfo/f/falco OLD_FILES+=usr/share/terminfo/f/falco-p OLD_FILES+=usr/share/terminfo/f/fbterm OLD_FILES+=usr/share/terminfo/f/fenix OLD_FILES+=usr/share/terminfo/f/fenixw OLD_FILES+=usr/share/terminfo/f/fixterm OLD_FILES+=usr/share/terminfo/f/fortune OLD_FILES+=usr/share/terminfo/f/fos OLD_FILES+=usr/share/terminfo/f/fox OLD_FILES+=usr/share/terminfo/f/freedom OLD_FILES+=usr/share/terminfo/f/freedom-rv OLD_FILES+=usr/share/terminfo/f/freedom100 OLD_FILES+=usr/share/terminfo/f/freedom110 OLD_FILES+=usr/share/terminfo/f/freedom200 OLD_DIRS+=usr/share/terminfo/f/ OLD_FILES+=usr/share/terminfo/g/gator OLD_FILES+=usr/share/terminfo/g/gator-52 OLD_FILES+=usr/share/terminfo/g/gator-52t OLD_FILES+=usr/share/terminfo/g/gator-t OLD_FILES+=usr/share/terminfo/g/gigi OLD_FILES+=usr/share/terminfo/g/glasstty OLD_FILES+=usr/share/terminfo/g/gnome OLD_FILES+=usr/share/terminfo/g/gnome+pcfkeys OLD_FILES+=usr/share/terminfo/g/gnome-2007 OLD_FILES+=usr/share/terminfo/g/gnome-2008 OLD_FILES+=usr/share/terminfo/g/gnome-2012 OLD_FILES+=usr/share/terminfo/g/gnome-256color OLD_FILES+=usr/share/terminfo/g/gnome-fc5 OLD_FILES+=usr/share/terminfo/g/gnome-rh62 OLD_FILES+=usr/share/terminfo/g/gnome-rh72 OLD_FILES+=usr/share/terminfo/g/gnome-rh80 OLD_FILES+=usr/share/terminfo/g/gnome-rh90 OLD_FILES+=usr/share/terminfo/g/go-225 OLD_FILES+=usr/share/terminfo/g/go140 OLD_FILES+=usr/share/terminfo/g/go140w OLD_FILES+=usr/share/terminfo/g/go225 OLD_FILES+=usr/share/terminfo/g/graphos OLD_FILES+=usr/share/terminfo/g/graphos-30 OLD_FILES+=usr/share/terminfo/g/gs5430 OLD_FILES+=usr/share/terminfo/g/gs5430-22 OLD_FILES+=usr/share/terminfo/g/gs5430-24 OLD_FILES+=usr/share/terminfo/g/gs6300 OLD_FILES+=usr/share/terminfo/g/gsi OLD_FILES+=usr/share/terminfo/g/gt100 OLD_FILES+=usr/share/terminfo/g/gt100a OLD_FILES+=usr/share/terminfo/g/gt40 OLD_FILES+=usr/share/terminfo/g/gt42 OLD_FILES+=usr/share/terminfo/g/guru OLD_FILES+=usr/share/terminfo/g/guru+rv OLD_FILES+=usr/share/terminfo/g/guru+s OLD_FILES+=usr/share/terminfo/g/guru+unk OLD_FILES+=usr/share/terminfo/g/guru-24 OLD_FILES+=usr/share/terminfo/g/guru-33 OLD_FILES+=usr/share/terminfo/g/guru-33-rv OLD_FILES+=usr/share/terminfo/g/guru-33-s OLD_FILES+=usr/share/terminfo/g/guru-44 OLD_FILES+=usr/share/terminfo/g/guru-44-s OLD_FILES+=usr/share/terminfo/g/guru-76 OLD_FILES+=usr/share/terminfo/g/guru-76-lp OLD_FILES+=usr/share/terminfo/g/guru-76-s OLD_FILES+=usr/share/terminfo/g/guru-76-w OLD_FILES+=usr/share/terminfo/g/guru-76-w-s OLD_FILES+=usr/share/terminfo/g/guru-76-wm OLD_FILES+=usr/share/terminfo/g/guru-lp OLD_FILES+=usr/share/terminfo/g/guru-nctxt OLD_FILES+=usr/share/terminfo/g/guru-rv OLD_FILES+=usr/share/terminfo/g/guru-s OLD_DIRS+=usr/share/terminfo/g/ OLD_FILES+=usr/share/terminfo/h/h-100 OLD_FILES+=usr/share/terminfo/h/h-100bw OLD_FILES+=usr/share/terminfo/h/h100 OLD_FILES+=usr/share/terminfo/h/h100bw OLD_FILES+=usr/share/terminfo/h/h19 OLD_FILES+=usr/share/terminfo/h/h19-a OLD_FILES+=usr/share/terminfo/h/h19-b OLD_FILES+=usr/share/terminfo/h/h19-bs OLD_FILES+=usr/share/terminfo/h/h19-g OLD_FILES+=usr/share/terminfo/h/h19-smul OLD_FILES+=usr/share/terminfo/h/h19-u OLD_FILES+=usr/share/terminfo/h/h19-us OLD_FILES+=usr/share/terminfo/h/h19a OLD_FILES+=usr/share/terminfo/h/h19g OLD_FILES+=usr/share/terminfo/h/h19k OLD_FILES+=usr/share/terminfo/h/h19kermit OLD_FILES+=usr/share/terminfo/h/h19us OLD_FILES+=usr/share/terminfo/h/h29a-kc-bc OLD_FILES+=usr/share/terminfo/h/h29a-kc-uc OLD_FILES+=usr/share/terminfo/h/h29a-nkc-bc OLD_FILES+=usr/share/terminfo/h/h29a-nkc-uc OLD_FILES+=usr/share/terminfo/h/h80 OLD_FILES+=usr/share/terminfo/h/ha8675 OLD_FILES+=usr/share/terminfo/h/ha8686 OLD_FILES+=usr/share/terminfo/h/hazel OLD_FILES+=usr/share/terminfo/h/hds200 OLD_FILES+=usr/share/terminfo/h/he80 OLD_FILES+=usr/share/terminfo/h/heath OLD_FILES+=usr/share/terminfo/h/heath-19 OLD_FILES+=usr/share/terminfo/h/heath-ansi OLD_FILES+=usr/share/terminfo/h/heathkit OLD_FILES+=usr/share/terminfo/h/heathkit-a OLD_FILES+=usr/share/terminfo/h/hft OLD_FILES+=usr/share/terminfo/h/hft-c OLD_FILES+=usr/share/terminfo/h/hft-c-old OLD_FILES+=usr/share/terminfo/h/hft-old OLD_FILES+=usr/share/terminfo/h/hirez100 OLD_FILES+=usr/share/terminfo/h/hirez100-w OLD_FILES+=usr/share/terminfo/h/hmod1 OLD_FILES+=usr/share/terminfo/h/hp OLD_FILES+=usr/share/terminfo/h/hp+arrows OLD_FILES+=usr/share/terminfo/h/hp+color OLD_FILES+=usr/share/terminfo/h/hp+labels OLD_FILES+=usr/share/terminfo/h/hp+pfk+arrows OLD_FILES+=usr/share/terminfo/h/hp+pfk+cr OLD_FILES+=usr/share/terminfo/h/hp+pfk-cr OLD_FILES+=usr/share/terminfo/h/hp+printer OLD_FILES+=usr/share/terminfo/h/hp110 OLD_FILES+=usr/share/terminfo/h/hp150 OLD_FILES+=usr/share/terminfo/h/hp2 OLD_FILES+=usr/share/terminfo/h/hp236 OLD_FILES+=usr/share/terminfo/h/hp2382 OLD_FILES+=usr/share/terminfo/h/hp2382a OLD_FILES+=usr/share/terminfo/h/hp2392 OLD_FILES+=usr/share/terminfo/h/hp2397 OLD_FILES+=usr/share/terminfo/h/hp2397a OLD_FILES+=usr/share/terminfo/h/hp2621 OLD_FILES+=usr/share/terminfo/h/hp2621-48 OLD_FILES+=usr/share/terminfo/h/hp2621-a OLD_FILES+=usr/share/terminfo/h/hp2621-ba OLD_FILES+=usr/share/terminfo/h/hp2621-fl OLD_FILES+=usr/share/terminfo/h/hp2621-k45 OLD_FILES+=usr/share/terminfo/h/hp2621-nl OLD_FILES+=usr/share/terminfo/h/hp2621-nt OLD_FILES+=usr/share/terminfo/h/hp2621-wl OLD_FILES+=usr/share/terminfo/h/hp2621A OLD_FILES+=usr/share/terminfo/h/hp2621a OLD_FILES+=usr/share/terminfo/h/hp2621a-a OLD_FILES+=usr/share/terminfo/h/hp2621b OLD_FILES+=usr/share/terminfo/h/hp2621b-kx OLD_FILES+=usr/share/terminfo/h/hp2621b-kx-p OLD_FILES+=usr/share/terminfo/h/hp2621b-p OLD_FILES+=usr/share/terminfo/h/hp2621k45 OLD_FILES+=usr/share/terminfo/h/hp2621p OLD_FILES+=usr/share/terminfo/h/hp2621p-a OLD_FILES+=usr/share/terminfo/h/hp2622 OLD_FILES+=usr/share/terminfo/h/hp2622a OLD_FILES+=usr/share/terminfo/h/hp2623 OLD_FILES+=usr/share/terminfo/h/hp2623a OLD_FILES+=usr/share/terminfo/h/hp2624 OLD_FILES+=usr/share/terminfo/h/hp2624-10p OLD_FILES+=usr/share/terminfo/h/hp2624a OLD_FILES+=usr/share/terminfo/h/hp2624a-10p OLD_FILES+=usr/share/terminfo/h/hp2624b OLD_FILES+=usr/share/terminfo/h/hp2624b-10p OLD_FILES+=usr/share/terminfo/h/hp2624b-10p-p OLD_FILES+=usr/share/terminfo/h/hp2624b-4p OLD_FILES+=usr/share/terminfo/h/hp2624b-4p-p OLD_FILES+=usr/share/terminfo/h/hp2624b-p OLD_FILES+=usr/share/terminfo/h/hp2626 OLD_FILES+=usr/share/terminfo/h/hp2626-12 OLD_FILES+=usr/share/terminfo/h/hp2626-12-s OLD_FILES+=usr/share/terminfo/h/hp2626-12x40 OLD_FILES+=usr/share/terminfo/h/hp2626-ns OLD_FILES+=usr/share/terminfo/h/hp2626-s OLD_FILES+=usr/share/terminfo/h/hp2626-x40 OLD_FILES+=usr/share/terminfo/h/hp2626a OLD_FILES+=usr/share/terminfo/h/hp2626p OLD_FILES+=usr/share/terminfo/h/hp2627a OLD_FILES+=usr/share/terminfo/h/hp2627a-rev OLD_FILES+=usr/share/terminfo/h/hp2627c OLD_FILES+=usr/share/terminfo/h/hp262x OLD_FILES+=usr/share/terminfo/h/hp2640a OLD_FILES+=usr/share/terminfo/h/hp2640b OLD_FILES+=usr/share/terminfo/h/hp2641a OLD_FILES+=usr/share/terminfo/h/hp2644a OLD_FILES+=usr/share/terminfo/h/hp2645 OLD_FILES+=usr/share/terminfo/h/hp2645a OLD_FILES+=usr/share/terminfo/h/hp2647a OLD_FILES+=usr/share/terminfo/h/hp2648 OLD_FILES+=usr/share/terminfo/h/hp2648a OLD_FILES+=usr/share/terminfo/h/hp300h OLD_FILES+=usr/share/terminfo/h/hp45 OLD_FILES+=usr/share/terminfo/h/hp700 OLD_FILES+=usr/share/terminfo/h/hp700-wy OLD_FILES+=usr/share/terminfo/h/hp70092 OLD_FILES+=usr/share/terminfo/h/hp70092A OLD_FILES+=usr/share/terminfo/h/hp70092a OLD_FILES+=usr/share/terminfo/h/hp9837 OLD_FILES+=usr/share/terminfo/h/hp9845 OLD_FILES+=usr/share/terminfo/h/hp98550 OLD_FILES+=usr/share/terminfo/h/hp98550a OLD_FILES+=usr/share/terminfo/h/hp98720 OLD_FILES+=usr/share/terminfo/h/hp98721 OLD_FILES+=usr/share/terminfo/h/hpansi OLD_FILES+=usr/share/terminfo/h/hpex OLD_FILES+=usr/share/terminfo/h/hpex2 OLD_FILES+=usr/share/terminfo/h/hpgeneric OLD_FILES+=usr/share/terminfo/h/hpsub OLD_FILES+=usr/share/terminfo/h/hpterm OLD_FILES+=usr/share/terminfo/h/hpterm-color OLD_FILES+=usr/share/terminfo/h/htx11 OLD_FILES+=usr/share/terminfo/h/hurd OLD_FILES+=usr/share/terminfo/h/hz1000 OLD_FILES+=usr/share/terminfo/h/hz1420 OLD_FILES+=usr/share/terminfo/h/hz1500 OLD_FILES+=usr/share/terminfo/h/hz1510 OLD_FILES+=usr/share/terminfo/h/hz1520 OLD_FILES+=usr/share/terminfo/h/hz1520-noesc OLD_FILES+=usr/share/terminfo/h/hz1552 OLD_FILES+=usr/share/terminfo/h/hz1552-rv OLD_FILES+=usr/share/terminfo/h/hz2000 OLD_DIRS+=usr/share/terminfo/h/ OLD_FILES+=usr/share/terminfo/i/i100 OLD_FILES+=usr/share/terminfo/i/i3101 OLD_FILES+=usr/share/terminfo/i/i3164 OLD_FILES+=usr/share/terminfo/i/i400 OLD_FILES+=usr/share/terminfo/i/iTerm.app OLD_FILES+=usr/share/terminfo/i/iTerm2.app OLD_FILES+=usr/share/terminfo/i/ibcs2 OLD_FILES+=usr/share/terminfo/i/ibm+16color OLD_FILES+=usr/share/terminfo/i/ibm+color OLD_FILES+=usr/share/terminfo/i/ibm-apl OLD_FILES+=usr/share/terminfo/i/ibm-pc OLD_FILES+=usr/share/terminfo/i/ibm-system1 OLD_FILES+=usr/share/terminfo/i/ibm3101 OLD_FILES+=usr/share/terminfo/i/ibm3151 OLD_FILES+=usr/share/terminfo/i/ibm3161 OLD_FILES+=usr/share/terminfo/i/ibm3161-C OLD_FILES+=usr/share/terminfo/i/ibm3162 OLD_FILES+=usr/share/terminfo/i/ibm3163 OLD_FILES+=usr/share/terminfo/i/ibm3164 OLD_FILES+=usr/share/terminfo/i/ibm327x OLD_FILES+=usr/share/terminfo/i/ibm5051 OLD_FILES+=usr/share/terminfo/i/ibm5081 OLD_FILES+=usr/share/terminfo/i/ibm5081-c OLD_FILES+=usr/share/terminfo/i/ibm5151 OLD_FILES+=usr/share/terminfo/i/ibm5154 OLD_FILES+=usr/share/terminfo/i/ibm5154-c OLD_FILES+=usr/share/terminfo/i/ibm6153 OLD_FILES+=usr/share/terminfo/i/ibm6153-40 OLD_FILES+=usr/share/terminfo/i/ibm6153-90 OLD_FILES+=usr/share/terminfo/i/ibm6154 OLD_FILES+=usr/share/terminfo/i/ibm6154-c OLD_FILES+=usr/share/terminfo/i/ibm6155 OLD_FILES+=usr/share/terminfo/i/ibm8503 OLD_FILES+=usr/share/terminfo/i/ibm8507 OLD_FILES+=usr/share/terminfo/i/ibm8512 OLD_FILES+=usr/share/terminfo/i/ibm8513 OLD_FILES+=usr/share/terminfo/i/ibm8514 OLD_FILES+=usr/share/terminfo/i/ibm8514-c OLD_FILES+=usr/share/terminfo/i/ibm8604 OLD_FILES+=usr/share/terminfo/i/ibmaed OLD_FILES+=usr/share/terminfo/i/ibmapa16 OLD_FILES+=usr/share/terminfo/i/ibmapa8 OLD_FILES+=usr/share/terminfo/i/ibmapa8c OLD_FILES+=usr/share/terminfo/i/ibmapa8c-c OLD_FILES+=usr/share/terminfo/i/ibmega OLD_FILES+=usr/share/terminfo/i/ibmega-c OLD_FILES+=usr/share/terminfo/i/ibmmono OLD_FILES+=usr/share/terminfo/i/ibmmpel-c OLD_FILES+=usr/share/terminfo/i/ibmpc OLD_FILES+=usr/share/terminfo/i/ibmpc3 OLD_FILES+=usr/share/terminfo/i/ibmpc3r OLD_FILES+=usr/share/terminfo/i/ibmpc3r-mono OLD_FILES+=usr/share/terminfo/i/ibmpcx OLD_FILES+=usr/share/terminfo/i/ibmvga OLD_FILES+=usr/share/terminfo/i/ibmvga-c OLD_FILES+=usr/share/terminfo/i/ibmx OLD_FILES+=usr/share/terminfo/i/icl6402 OLD_FILES+=usr/share/terminfo/i/icl6404 OLD_FILES+=usr/share/terminfo/i/icl6404-w OLD_FILES+=usr/share/terminfo/i/ifmr OLD_FILES+=usr/share/terminfo/i/ims-ansi OLD_FILES+=usr/share/terminfo/i/ims950 OLD_FILES+=usr/share/terminfo/i/ims950-b OLD_FILES+=usr/share/terminfo/i/ims950-rv OLD_FILES+=usr/share/terminfo/i/infoton OLD_FILES+=usr/share/terminfo/i/interix OLD_FILES+=usr/share/terminfo/i/interix-nti OLD_FILES+=usr/share/terminfo/i/intertec OLD_FILES+=usr/share/terminfo/i/intertube OLD_FILES+=usr/share/terminfo/i/intertube2 OLD_FILES+=usr/share/terminfo/i/intext OLD_FILES+=usr/share/terminfo/i/intext2 OLD_FILES+=usr/share/terminfo/i/intextii OLD_FILES+=usr/share/terminfo/i/ips OLD_FILES+=usr/share/terminfo/i/ipsi OLD_FILES+=usr/share/terminfo/i/iq120 OLD_FILES+=usr/share/terminfo/i/iq140 OLD_FILES+=usr/share/terminfo/i/iris-ansi OLD_FILES+=usr/share/terminfo/i/iris-ansi-ap OLD_FILES+=usr/share/terminfo/i/iris-ansi-net OLD_FILES+=usr/share/terminfo/i/iris-color OLD_FILES+=usr/share/terminfo/i/iris40 OLD_FILES+=usr/share/terminfo/i/iterm OLD_FILES+=usr/share/terminfo/i/iterm2 OLD_FILES+=usr/share/terminfo/i/iterm2-direct OLD_DIRS+=usr/share/terminfo/i/ OLD_FILES+=usr/share/terminfo/j/jaixterm OLD_FILES+=usr/share/terminfo/j/jaixterm-m OLD_FILES+=usr/share/terminfo/j/jerq OLD_FILES+=usr/share/terminfo/j/jfbterm OLD_DIRS+=usr/share/terminfo/j/ OLD_FILES+=usr/share/terminfo/k/k45 OLD_FILES+=usr/share/terminfo/k/kaypro OLD_FILES+=usr/share/terminfo/k/kaypro2 OLD_FILES+=usr/share/terminfo/k/kds6402 OLD_FILES+=usr/share/terminfo/k/kds7372 OLD_FILES+=usr/share/terminfo/k/kds7372-w OLD_FILES+=usr/share/terminfo/k/kermit OLD_FILES+=usr/share/terminfo/k/kermit-am OLD_FILES+=usr/share/terminfo/k/kitty OLD_FILES+=usr/share/terminfo/k/kitty+common OLD_FILES+=usr/share/terminfo/k/kitty-direct OLD_FILES+=usr/share/terminfo/k/klone+acs OLD_FILES+=usr/share/terminfo/k/klone+color OLD_FILES+=usr/share/terminfo/k/klone+koi8acs OLD_FILES+=usr/share/terminfo/k/klone+sgr OLD_FILES+=usr/share/terminfo/k/klone+sgr-dumb OLD_FILES+=usr/share/terminfo/k/klone+sgr8 OLD_FILES+=usr/share/terminfo/k/kon OLD_FILES+=usr/share/terminfo/k/kon2 OLD_FILES+=usr/share/terminfo/k/konsole OLD_FILES+=usr/share/terminfo/k/konsole+pcfkeys OLD_FILES+=usr/share/terminfo/k/konsole-16color OLD_FILES+=usr/share/terminfo/k/konsole-256color OLD_FILES+=usr/share/terminfo/k/konsole-base OLD_FILES+=usr/share/terminfo/k/konsole-direct OLD_FILES+=usr/share/terminfo/k/konsole-linux OLD_FILES+=usr/share/terminfo/k/konsole-solaris OLD_FILES+=usr/share/terminfo/k/konsole-vt100 OLD_FILES+=usr/share/terminfo/k/konsole-vt420pc OLD_FILES+=usr/share/terminfo/k/konsole-xf3x OLD_FILES+=usr/share/terminfo/k/konsole-xf4x OLD_FILES+=usr/share/terminfo/k/kt7 OLD_FILES+=usr/share/terminfo/k/kt7ix OLD_FILES+=usr/share/terminfo/k/kterm OLD_FILES+=usr/share/terminfo/k/kterm-co OLD_FILES+=usr/share/terminfo/k/kterm-color OLD_FILES+=usr/share/terminfo/k/ktm OLD_FILES+=usr/share/terminfo/k/kvt OLD_DIRS+=usr/share/terminfo/k/ OLD_FILES+=usr/share/terminfo/l/la120 OLD_FILES+=usr/share/terminfo/l/layer OLD_FILES+=usr/share/terminfo/l/lft OLD_FILES+=usr/share/terminfo/l/lft-pc850 OLD_FILES+=usr/share/terminfo/l/linux OLD_FILES+=usr/share/terminfo/l/linux+decid OLD_FILES+=usr/share/terminfo/l/linux+sfkeys OLD_FILES+=usr/share/terminfo/l/linux-16color OLD_FILES+=usr/share/terminfo/l/linux-basic OLD_FILES+=usr/share/terminfo/l/linux-c OLD_FILES+=usr/share/terminfo/l/linux-c-nc OLD_FILES+=usr/share/terminfo/l/linux-koi8 OLD_FILES+=usr/share/terminfo/l/linux-koi8r OLD_FILES+=usr/share/terminfo/l/linux-lat OLD_FILES+=usr/share/terminfo/l/linux-m OLD_FILES+=usr/share/terminfo/l/linux-m1 OLD_FILES+=usr/share/terminfo/l/linux-m1b OLD_FILES+=usr/share/terminfo/l/linux-m2 OLD_FILES+=usr/share/terminfo/l/linux-nic OLD_FILES+=usr/share/terminfo/l/linux-s OLD_FILES+=usr/share/terminfo/l/linux-vt OLD_FILES+=usr/share/terminfo/l/linux2.2 OLD_FILES+=usr/share/terminfo/l/linux2.6 OLD_FILES+=usr/share/terminfo/l/linux2.6.26 OLD_FILES+=usr/share/terminfo/l/linux3.0 OLD_FILES+=usr/share/terminfo/l/lisa OLD_FILES+=usr/share/terminfo/l/lisaterm OLD_FILES+=usr/share/terminfo/l/lisaterm-w OLD_FILES+=usr/share/terminfo/l/liswb OLD_FILES+=usr/share/terminfo/l/ln03 OLD_FILES+=usr/share/terminfo/l/ln03-w OLD_FILES+=usr/share/terminfo/l/lpr OLD_FILES+=usr/share/terminfo/l/luna OLD_FILES+=usr/share/terminfo/l/luna68k OLD_DIRS+=usr/share/terminfo/l/ OLD_FILES+=usr/share/terminfo/m/m2-nam OLD_FILES+=usr/share/terminfo/m/mac OLD_FILES+=usr/share/terminfo/m/mac-w OLD_FILES+=usr/share/terminfo/m/mach OLD_FILES+=usr/share/terminfo/m/mach-bold OLD_FILES+=usr/share/terminfo/m/mach-color OLD_FILES+=usr/share/terminfo/m/mach-gnu OLD_FILES+=usr/share/terminfo/m/mach-gnu-color OLD_FILES+=usr/share/terminfo/m/macintosh OLD_FILES+=usr/share/terminfo/m/macterminal-w OLD_FILES+=usr/share/terminfo/m/mai OLD_FILES+=usr/share/terminfo/m/masscomp OLD_FILES+=usr/share/terminfo/m/masscomp1 OLD_FILES+=usr/share/terminfo/m/masscomp2 OLD_FILES+=usr/share/terminfo/m/mdl110 OLD_FILES+=usr/share/terminfo/m/megatek OLD_FILES+=usr/share/terminfo/m/memhp OLD_FILES+=usr/share/terminfo/m/mgr OLD_FILES+=usr/share/terminfo/m/mgr-linux OLD_FILES+=usr/share/terminfo/m/mgr-sun OLD_FILES+=usr/share/terminfo/m/mgt OLD_FILES+=usr/share/terminfo/m/mgterm OLD_FILES+=usr/share/terminfo/m/microb OLD_FILES+=usr/share/terminfo/m/microbee OLD_FILES+=usr/share/terminfo/m/microterm OLD_FILES+=usr/share/terminfo/m/microterm5 OLD_FILES+=usr/share/terminfo/m/mime OLD_FILES+=usr/share/terminfo/m/mime-3ax OLD_FILES+=usr/share/terminfo/m/mime-fb OLD_FILES+=usr/share/terminfo/m/mime-hb OLD_FILES+=usr/share/terminfo/m/mime1 OLD_FILES+=usr/share/terminfo/m/mime2 OLD_FILES+=usr/share/terminfo/m/mime2a OLD_FILES+=usr/share/terminfo/m/mime2a-s OLD_FILES+=usr/share/terminfo/m/mime2a-v OLD_FILES+=usr/share/terminfo/m/mime314 OLD_FILES+=usr/share/terminfo/m/mime340 OLD_FILES+=usr/share/terminfo/m/mime3a OLD_FILES+=usr/share/terminfo/m/mime3ax OLD_FILES+=usr/share/terminfo/m/mimei OLD_FILES+=usr/share/terminfo/m/mimeii OLD_FILES+=usr/share/terminfo/m/minitel OLD_FILES+=usr/share/terminfo/m/minitel-2 OLD_FILES+=usr/share/terminfo/m/minitel-2-nam OLD_FILES+=usr/share/terminfo/m/minitel1 OLD_FILES+=usr/share/terminfo/m/minitel1-nb OLD_FILES+=usr/share/terminfo/m/minitel12-80 OLD_FILES+=usr/share/terminfo/m/minitel1b OLD_FILES+=usr/share/terminfo/m/minitel1b-80 OLD_FILES+=usr/share/terminfo/m/minitel1b-nb OLD_FILES+=usr/share/terminfo/m/minitel2-80 OLD_FILES+=usr/share/terminfo/m/minix OLD_FILES+=usr/share/terminfo/m/minix-1.5 OLD_FILES+=usr/share/terminfo/m/minix-1.7 OLD_FILES+=usr/share/terminfo/m/minix-3.0 OLD_FILES+=usr/share/terminfo/m/minix-old OLD_FILES+=usr/share/terminfo/m/minix-old-am OLD_FILES+=usr/share/terminfo/m/mintty OLD_FILES+=usr/share/terminfo/m/mintty+common OLD_FILES+=usr/share/terminfo/m/mintty-direct OLD_FILES+=usr/share/terminfo/m/mlterm OLD_FILES+=usr/share/terminfo/m/mlterm+pcfkeys OLD_FILES+=usr/share/terminfo/m/mlterm-256color OLD_FILES+=usr/share/terminfo/m/mlterm-direct OLD_FILES+=usr/share/terminfo/m/mlterm2 OLD_FILES+=usr/share/terminfo/m/mlterm3 OLD_FILES+=usr/share/terminfo/m/mm314 OLD_FILES+=usr/share/terminfo/m/mm340 OLD_FILES+=usr/share/terminfo/m/mod OLD_FILES+=usr/share/terminfo/m/mod24 OLD_FILES+=usr/share/terminfo/m/modgraph OLD_FILES+=usr/share/terminfo/m/modgraph2 OLD_FILES+=usr/share/terminfo/m/modgraph48 OLD_FILES+=usr/share/terminfo/m/mono-emx OLD_FILES+=usr/share/terminfo/m/morphos OLD_FILES+=usr/share/terminfo/m/mouse-sun OLD_FILES+=usr/share/terminfo/m/mrxvt OLD_FILES+=usr/share/terminfo/m/mrxvt-256color OLD_FILES+=usr/share/terminfo/m/ms-terminal OLD_FILES+=usr/share/terminfo/m/ms-vt-utf8 OLD_FILES+=usr/share/terminfo/m/ms-vt100 OLD_FILES+=usr/share/terminfo/m/ms-vt100+ OLD_FILES+=usr/share/terminfo/m/ms-vt100-color OLD_FILES+=usr/share/terminfo/m/msk227 OLD_FILES+=usr/share/terminfo/m/msk22714 OLD_FILES+=usr/share/terminfo/m/msk227am OLD_FILES+=usr/share/terminfo/m/mskermit227 OLD_FILES+=usr/share/terminfo/m/mskermit22714 OLD_FILES+=usr/share/terminfo/m/mskermit227am OLD_FILES+=usr/share/terminfo/m/mt-70 OLD_FILES+=usr/share/terminfo/m/mt4520-rv OLD_FILES+=usr/share/terminfo/m/mt70 OLD_FILES+=usr/share/terminfo/m/mterm OLD_FILES+=usr/share/terminfo/m/mterm-ansi OLD_FILES+=usr/share/terminfo/m/mvterm OLD_DIRS+=usr/share/terminfo/m/ OLD_FILES+=usr/share/terminfo/n/n7900 OLD_FILES+=usr/share/terminfo/n/nansi.sys OLD_FILES+=usr/share/terminfo/n/nansi.sysk OLD_FILES+=usr/share/terminfo/n/nansisys OLD_FILES+=usr/share/terminfo/n/nansisysk OLD_FILES+=usr/share/terminfo/n/ncr160vppp OLD_FILES+=usr/share/terminfo/n/ncr160vpwpp OLD_FILES+=usr/share/terminfo/n/ncr160vt100an OLD_FILES+=usr/share/terminfo/n/ncr160vt100pp OLD_FILES+=usr/share/terminfo/n/ncr160vt100wan OLD_FILES+=usr/share/terminfo/n/ncr160vt100wpp OLD_FILES+=usr/share/terminfo/n/ncr160vt200an OLD_FILES+=usr/share/terminfo/n/ncr160vt200pp OLD_FILES+=usr/share/terminfo/n/ncr160vt200wan OLD_FILES+=usr/share/terminfo/n/ncr160vt200wpp OLD_FILES+=usr/share/terminfo/n/ncr160vt300an OLD_FILES+=usr/share/terminfo/n/ncr160vt300pp OLD_FILES+=usr/share/terminfo/n/ncr160vt300wan OLD_FILES+=usr/share/terminfo/n/ncr160vt300wpp OLD_FILES+=usr/share/terminfo/n/ncr160wy50+pp OLD_FILES+=usr/share/terminfo/n/ncr160wy50+wpp OLD_FILES+=usr/share/terminfo/n/ncr160wy60pp OLD_FILES+=usr/share/terminfo/n/ncr160wy60wpp OLD_FILES+=usr/share/terminfo/n/ncr260intan OLD_FILES+=usr/share/terminfo/n/ncr260intpp OLD_FILES+=usr/share/terminfo/n/ncr260intwan OLD_FILES+=usr/share/terminfo/n/ncr260intwpp OLD_FILES+=usr/share/terminfo/n/ncr260vppp OLD_FILES+=usr/share/terminfo/n/ncr260vpwpp OLD_FILES+=usr/share/terminfo/n/ncr260vt100an OLD_FILES+=usr/share/terminfo/n/ncr260vt100pp OLD_FILES+=usr/share/terminfo/n/ncr260vt100wan OLD_FILES+=usr/share/terminfo/n/ncr260vt100wpp OLD_FILES+=usr/share/terminfo/n/ncr260vt200an OLD_FILES+=usr/share/terminfo/n/ncr260vt200pp OLD_FILES+=usr/share/terminfo/n/ncr260vt200wan OLD_FILES+=usr/share/terminfo/n/ncr260vt200wpp OLD_FILES+=usr/share/terminfo/n/ncr260vt300an OLD_FILES+=usr/share/terminfo/n/ncr260vt300pp OLD_FILES+=usr/share/terminfo/n/ncr260vt300wan OLD_FILES+=usr/share/terminfo/n/ncr260vt300wpp OLD_FILES+=usr/share/terminfo/n/ncr260wy325pp OLD_FILES+=usr/share/terminfo/n/ncr260wy325wpp OLD_FILES+=usr/share/terminfo/n/ncr260wy350pp OLD_FILES+=usr/share/terminfo/n/ncr260wy350wpp OLD_FILES+=usr/share/terminfo/n/ncr260wy50+pp OLD_FILES+=usr/share/terminfo/n/ncr260wy50+wpp OLD_FILES+=usr/share/terminfo/n/ncr260wy60pp OLD_FILES+=usr/share/terminfo/n/ncr260wy60wpp OLD_FILES+=usr/share/terminfo/n/ncr7900 OLD_FILES+=usr/share/terminfo/n/ncr7900i OLD_FILES+=usr/share/terminfo/n/ncr7900iv OLD_FILES+=usr/share/terminfo/n/ncr7901 OLD_FILES+=usr/share/terminfo/n/ncrvt100an OLD_FILES+=usr/share/terminfo/n/ncrvt100pp OLD_FILES+=usr/share/terminfo/n/ncrvt100wan OLD_FILES+=usr/share/terminfo/n/ncrvt100wpp OLD_FILES+=usr/share/terminfo/n/ncsa OLD_FILES+=usr/share/terminfo/n/ncsa-m OLD_FILES+=usr/share/terminfo/n/ncsa-m-ns OLD_FILES+=usr/share/terminfo/n/ncsa-ns OLD_FILES+=usr/share/terminfo/n/ncsa-vt220 OLD_FILES+=usr/share/terminfo/n/ncsa-vt220-8 OLD_FILES+=usr/share/terminfo/n/nd9500 OLD_FILES+=usr/share/terminfo/n/ndr9500 OLD_FILES+=usr/share/terminfo/n/ndr9500-25 OLD_FILES+=usr/share/terminfo/n/ndr9500-25-mc OLD_FILES+=usr/share/terminfo/n/ndr9500-25-mc-nl OLD_FILES+=usr/share/terminfo/n/ndr9500-25-nl OLD_FILES+=usr/share/terminfo/n/ndr9500-mc OLD_FILES+=usr/share/terminfo/n/ndr9500-mc-nl OLD_FILES+=usr/share/terminfo/n/ndr9500-nl OLD_FILES+=usr/share/terminfo/n/nec OLD_FILES+=usr/share/terminfo/n/nec5520 OLD_FILES+=usr/share/terminfo/n/netbsd6 OLD_FILES+=usr/share/terminfo/n/newhp OLD_FILES+=usr/share/terminfo/n/newhpkeyboard OLD_FILES+=usr/share/terminfo/n/news OLD_FILES+=usr/share/terminfo/n/news-29 OLD_FILES+=usr/share/terminfo/n/news-29-euc OLD_FILES+=usr/share/terminfo/n/news-29-sjis OLD_FILES+=usr/share/terminfo/n/news-33 OLD_FILES+=usr/share/terminfo/n/news-33-euc OLD_FILES+=usr/share/terminfo/n/news-33-sjis OLD_FILES+=usr/share/terminfo/n/news-42 OLD_FILES+=usr/share/terminfo/n/news-42-euc OLD_FILES+=usr/share/terminfo/n/news-42-sjis OLD_FILES+=usr/share/terminfo/n/news-a OLD_FILES+=usr/share/terminfo/n/news-o OLD_FILES+=usr/share/terminfo/n/news-old-unk OLD_FILES+=usr/share/terminfo/n/news-unk OLD_FILES+=usr/share/terminfo/n/news28 OLD_FILES+=usr/share/terminfo/n/news28-a OLD_FILES+=usr/share/terminfo/n/news29 OLD_FILES+=usr/share/terminfo/n/news31 OLD_FILES+=usr/share/terminfo/n/news31-a OLD_FILES+=usr/share/terminfo/n/news31-o OLD_FILES+=usr/share/terminfo/n/news33 OLD_FILES+=usr/share/terminfo/n/news40 OLD_FILES+=usr/share/terminfo/n/news40-a OLD_FILES+=usr/share/terminfo/n/news40-o OLD_FILES+=usr/share/terminfo/n/news42 OLD_FILES+=usr/share/terminfo/n/newscbm OLD_FILES+=usr/share/terminfo/n/newscbm-a OLD_FILES+=usr/share/terminfo/n/newscbm-o OLD_FILES+=usr/share/terminfo/n/newscbm33 OLD_FILES+=usr/share/terminfo/n/next OLD_FILES+=usr/share/terminfo/n/nextshell OLD_FILES+=usr/share/terminfo/n/northstar OLD_FILES+=usr/share/terminfo/n/nsterm OLD_FILES+=usr/share/terminfo/n/nsterm+7 OLD_FILES+=usr/share/terminfo/n/nsterm+acs OLD_FILES+=usr/share/terminfo/n/nsterm+c OLD_FILES+=usr/share/terminfo/n/nsterm+c41 OLD_FILES+=usr/share/terminfo/n/nsterm+mac OLD_FILES+=usr/share/terminfo/n/nsterm+s OLD_FILES+=usr/share/terminfo/n/nsterm-16color OLD_FILES+=usr/share/terminfo/n/nsterm-256color OLD_FILES+=usr/share/terminfo/n/nsterm-7 OLD_FILES+=usr/share/terminfo/n/nsterm-7-c OLD_FILES+=usr/share/terminfo/n/nsterm-7-c-s OLD_FILES+=usr/share/terminfo/n/nsterm-7-m OLD_FILES+=usr/share/terminfo/n/nsterm-7-m-s OLD_FILES+=usr/share/terminfo/n/nsterm-7-s OLD_FILES+=usr/share/terminfo/n/nsterm-acs OLD_FILES+=usr/share/terminfo/n/nsterm-acs-c OLD_FILES+=usr/share/terminfo/n/nsterm-acs-c-s OLD_FILES+=usr/share/terminfo/n/nsterm-acs-m OLD_FILES+=usr/share/terminfo/n/nsterm-acs-m-s OLD_FILES+=usr/share/terminfo/n/nsterm-acs-s OLD_FILES+=usr/share/terminfo/n/nsterm-bce OLD_FILES+=usr/share/terminfo/n/nsterm-build309 OLD_FILES+=usr/share/terminfo/n/nsterm-build326 OLD_FILES+=usr/share/terminfo/n/nsterm-build343 OLD_FILES+=usr/share/terminfo/n/nsterm-build361 OLD_FILES+=usr/share/terminfo/n/nsterm-build400 OLD_FILES+=usr/share/terminfo/n/nsterm-c OLD_FILES+=usr/share/terminfo/n/nsterm-c-7 OLD_FILES+=usr/share/terminfo/n/nsterm-c-acs OLD_FILES+=usr/share/terminfo/n/nsterm-c-s OLD_FILES+=usr/share/terminfo/n/nsterm-c-s-7 OLD_FILES+=usr/share/terminfo/n/nsterm-c-s-acs OLD_FILES+=usr/share/terminfo/n/nsterm-direct OLD_FILES+=usr/share/terminfo/n/nsterm-m OLD_FILES+=usr/share/terminfo/n/nsterm-m-7 OLD_FILES+=usr/share/terminfo/n/nsterm-m-acs OLD_FILES+=usr/share/terminfo/n/nsterm-m-s OLD_FILES+=usr/share/terminfo/n/nsterm-m-s-7 OLD_FILES+=usr/share/terminfo/n/nsterm-m-s-acs OLD_FILES+=usr/share/terminfo/n/nsterm-old OLD_FILES+=usr/share/terminfo/n/nsterm-s OLD_FILES+=usr/share/terminfo/n/nsterm-s-7 OLD_FILES+=usr/share/terminfo/n/nsterm-s-acs OLD_FILES+=usr/share/terminfo/n/ntconsole OLD_FILES+=usr/share/terminfo/n/ntconsole-100 OLD_FILES+=usr/share/terminfo/n/ntconsole-100-nti OLD_FILES+=usr/share/terminfo/n/ntconsole-25 OLD_FILES+=usr/share/terminfo/n/ntconsole-25-nti OLD_FILES+=usr/share/terminfo/n/ntconsole-25-w OLD_FILES+=usr/share/terminfo/n/ntconsole-25-w-vt OLD_FILES+=usr/share/terminfo/n/ntconsole-35 OLD_FILES+=usr/share/terminfo/n/ntconsole-35-nti OLD_FILES+=usr/share/terminfo/n/ntconsole-35-w OLD_FILES+=usr/share/terminfo/n/ntconsole-50 OLD_FILES+=usr/share/terminfo/n/ntconsole-50-nti OLD_FILES+=usr/share/terminfo/n/ntconsole-50-w OLD_FILES+=usr/share/terminfo/n/ntconsole-60 OLD_FILES+=usr/share/terminfo/n/ntconsole-60-nti OLD_FILES+=usr/share/terminfo/n/ntconsole-60-w OLD_FILES+=usr/share/terminfo/n/ntconsole-w OLD_FILES+=usr/share/terminfo/n/ntconsole-w-vt OLD_FILES+=usr/share/terminfo/n/nwe501 OLD_FILES+=usr/share/terminfo/n/nwe501-a OLD_FILES+=usr/share/terminfo/n/nwe501-o OLD_FILES+=usr/share/terminfo/n/nwp-511 OLD_FILES+=usr/share/terminfo/n/nwp-517 OLD_FILES+=usr/share/terminfo/n/nwp-517-w OLD_FILES+=usr/share/terminfo/n/nwp251-a OLD_FILES+=usr/share/terminfo/n/nwp251-o OLD_FILES+=usr/share/terminfo/n/nwp511 OLD_FILES+=usr/share/terminfo/n/nwp512 OLD_FILES+=usr/share/terminfo/n/nwp512-a OLD_FILES+=usr/share/terminfo/n/nwp512-o OLD_FILES+=usr/share/terminfo/n/nwp513 OLD_FILES+=usr/share/terminfo/n/nwp513-a OLD_FILES+=usr/share/terminfo/n/nwp513-o OLD_FILES+=usr/share/terminfo/n/nwp514 OLD_FILES+=usr/share/terminfo/n/nwp514-a OLD_FILES+=usr/share/terminfo/n/nwp514-o OLD_FILES+=usr/share/terminfo/n/nwp517 OLD_FILES+=usr/share/terminfo/n/nwp517-w OLD_FILES+=usr/share/terminfo/n/nwp518 OLD_FILES+=usr/share/terminfo/n/nwp518-a OLD_FILES+=usr/share/terminfo/n/nwp518-o OLD_FILES+=usr/share/terminfo/n/nxterm OLD_DIRS+=usr/share/terminfo/n/ OLD_FILES+=usr/share/terminfo/o/o31 OLD_FILES+=usr/share/terminfo/o/o4112-nd OLD_FILES+=usr/share/terminfo/o/o85h OLD_FILES+=usr/share/terminfo/o/oabm85h OLD_FILES+=usr/share/terminfo/o/oblit OLD_FILES+=usr/share/terminfo/o/oc100 OLD_FILES+=usr/share/terminfo/o/oconcept OLD_FILES+=usr/share/terminfo/o/ofcons OLD_FILES+=usr/share/terminfo/o/ojerq OLD_FILES+=usr/share/terminfo/o/old-st OLD_FILES+=usr/share/terminfo/o/oldibmpc3 OLD_FILES+=usr/share/terminfo/o/oldpc3 OLD_FILES+=usr/share/terminfo/o/oldsun OLD_FILES+=usr/share/terminfo/o/omron OLD_FILES+=usr/share/terminfo/o/opennt OLD_FILES+=usr/share/terminfo/o/opennt-100 OLD_FILES+=usr/share/terminfo/o/opennt-100-nti OLD_FILES+=usr/share/terminfo/o/opennt-25 OLD_FILES+=usr/share/terminfo/o/opennt-25-nti OLD_FILES+=usr/share/terminfo/o/opennt-25-w OLD_FILES+=usr/share/terminfo/o/opennt-25-w-vt OLD_FILES+=usr/share/terminfo/o/opennt-35 OLD_FILES+=usr/share/terminfo/o/opennt-35-nti OLD_FILES+=usr/share/terminfo/o/opennt-35-w OLD_FILES+=usr/share/terminfo/o/opennt-50 OLD_FILES+=usr/share/terminfo/o/opennt-50-nti OLD_FILES+=usr/share/terminfo/o/opennt-50-w OLD_FILES+=usr/share/terminfo/o/opennt-60 OLD_FILES+=usr/share/terminfo/o/opennt-60-nti OLD_FILES+=usr/share/terminfo/o/opennt-60-w OLD_FILES+=usr/share/terminfo/o/opennt-nti OLD_FILES+=usr/share/terminfo/o/opennt-w OLD_FILES+=usr/share/terminfo/o/opennt-w-vt OLD_FILES+=usr/share/terminfo/o/opus3n1+ OLD_FILES+=usr/share/terminfo/o/origibmpc3 OLD_FILES+=usr/share/terminfo/o/origpc3 OLD_FILES+=usr/share/terminfo/o/os9LII OLD_FILES+=usr/share/terminfo/o/osborne OLD_FILES+=usr/share/terminfo/o/osborne-w OLD_FILES+=usr/share/terminfo/o/osborne1 OLD_FILES+=usr/share/terminfo/o/osborne1-w OLD_FILES+=usr/share/terminfo/o/osexec OLD_FILES+=usr/share/terminfo/o/otek4112 OLD_FILES+=usr/share/terminfo/o/otek4113 OLD_FILES+=usr/share/terminfo/o/otek4114 OLD_FILES+=usr/share/terminfo/o/otek4115 OLD_FILES+=usr/share/terminfo/o/owl OLD_DIRS+=usr/share/terminfo/o/ OLD_FILES+=usr/share/terminfo/p/p12 OLD_FILES+=usr/share/terminfo/p/p12-m OLD_FILES+=usr/share/terminfo/p/p12-m-w OLD_FILES+=usr/share/terminfo/p/p12-w OLD_FILES+=usr/share/terminfo/p/p14 OLD_FILES+=usr/share/terminfo/p/p14-m OLD_FILES+=usr/share/terminfo/p/p14-m-w OLD_FILES+=usr/share/terminfo/p/p14-w OLD_FILES+=usr/share/terminfo/p/p19 OLD_FILES+=usr/share/terminfo/p/p4 OLD_FILES+=usr/share/terminfo/p/p5 OLD_FILES+=usr/share/terminfo/p/p7 OLD_FILES+=usr/share/terminfo/p/p8 OLD_FILES+=usr/share/terminfo/p/p8-w OLD_FILES+=usr/share/terminfo/p/p8gl OLD_FILES+=usr/share/terminfo/p/p9 OLD_FILES+=usr/share/terminfo/p/p9-8 OLD_FILES+=usr/share/terminfo/p/p9-8-w OLD_FILES+=usr/share/terminfo/p/p9-w OLD_FILES+=usr/share/terminfo/p/pc-coherent OLD_FILES+=usr/share/terminfo/p/pc-minix OLD_FILES+=usr/share/terminfo/p/pc-venix OLD_FILES+=usr/share/terminfo/p/pc3 OLD_FILES+=usr/share/terminfo/p/pc3-bold OLD_FILES+=usr/share/terminfo/p/pc3r OLD_FILES+=usr/share/terminfo/p/pc3r-m OLD_FILES+=usr/share/terminfo/p/pc6300plus OLD_FILES+=usr/share/terminfo/p/pc7300 OLD_FILES+=usr/share/terminfo/p/pcansi OLD_FILES+=usr/share/terminfo/p/pcansi-25 OLD_FILES+=usr/share/terminfo/p/pcansi-25-m OLD_FILES+=usr/share/terminfo/p/pcansi-33 OLD_FILES+=usr/share/terminfo/p/pcansi-33-m OLD_FILES+=usr/share/terminfo/p/pcansi-43 OLD_FILES+=usr/share/terminfo/p/pcansi-43-m OLD_FILES+=usr/share/terminfo/p/pcansi-m OLD_FILES+=usr/share/terminfo/p/pcansi-mono OLD_FILES+=usr/share/terminfo/p/pcansi25 OLD_FILES+=usr/share/terminfo/p/pcansi25m OLD_FILES+=usr/share/terminfo/p/pcansi33 OLD_FILES+=usr/share/terminfo/p/pcansi33m OLD_FILES+=usr/share/terminfo/p/pcansi43 OLD_FILES+=usr/share/terminfo/p/pccon OLD_FILES+=usr/share/terminfo/p/pccon+base OLD_FILES+=usr/share/terminfo/p/pccon+colors OLD_FILES+=usr/share/terminfo/p/pccon+keys OLD_FILES+=usr/share/terminfo/p/pccon+sgr+acs OLD_FILES+=usr/share/terminfo/p/pccon+sgr+acs0 OLD_FILES+=usr/share/terminfo/p/pccon-m OLD_FILES+=usr/share/terminfo/p/pccon0 OLD_FILES+=usr/share/terminfo/p/pccon0-m OLD_FILES+=usr/share/terminfo/p/pccons OLD_FILES+=usr/share/terminfo/p/pcconsole OLD_FILES+=usr/share/terminfo/p/pcix OLD_FILES+=usr/share/terminfo/p/pckermit OLD_FILES+=usr/share/terminfo/p/pckermit12 OLD_FILES+=usr/share/terminfo/p/pckermit120 OLD_FILES+=usr/share/terminfo/p/pcmw OLD_FILES+=usr/share/terminfo/p/pcplot OLD_FILES+=usr/share/terminfo/p/pcvt25 OLD_FILES+=usr/share/terminfo/p/pcvt25-color OLD_FILES+=usr/share/terminfo/p/pcvt25w OLD_FILES+=usr/share/terminfo/p/pcvt28 OLD_FILES+=usr/share/terminfo/p/pcvt28w OLD_FILES+=usr/share/terminfo/p/pcvt35 OLD_FILES+=usr/share/terminfo/p/pcvt35w OLD_FILES+=usr/share/terminfo/p/pcvt40 OLD_FILES+=usr/share/terminfo/p/pcvt40w OLD_FILES+=usr/share/terminfo/p/pcvt43 OLD_FILES+=usr/share/terminfo/p/pcvt43w OLD_FILES+=usr/share/terminfo/p/pcvt50 OLD_FILES+=usr/share/terminfo/p/pcvt50w OLD_FILES+=usr/share/terminfo/p/pcvtXX OLD_FILES+=usr/share/terminfo/p/pcz19 OLD_FILES+=usr/share/terminfo/p/pe1100 OLD_FILES+=usr/share/terminfo/p/pe1200 OLD_FILES+=usr/share/terminfo/p/pe1251 OLD_FILES+=usr/share/terminfo/p/pe550 OLD_FILES+=usr/share/terminfo/p/pe6100 OLD_FILES+=usr/share/terminfo/p/pe6300 OLD_FILES+=usr/share/terminfo/p/pe6312 OLD_FILES+=usr/share/terminfo/p/pe7000c OLD_FILES+=usr/share/terminfo/p/pe7000m OLD_FILES+=usr/share/terminfo/p/pilot OLD_FILES+=usr/share/terminfo/p/pmcons OLD_FILES+=usr/share/terminfo/p/pmconsole OLD_FILES+=usr/share/terminfo/p/printer OLD_FILES+=usr/share/terminfo/p/prism12 OLD_FILES+=usr/share/terminfo/p/prism12-m OLD_FILES+=usr/share/terminfo/p/prism12-m-w OLD_FILES+=usr/share/terminfo/p/prism12-w OLD_FILES+=usr/share/terminfo/p/prism14 OLD_FILES+=usr/share/terminfo/p/prism14-m OLD_FILES+=usr/share/terminfo/p/prism14-m-w OLD_FILES+=usr/share/terminfo/p/prism14-w OLD_FILES+=usr/share/terminfo/p/prism2 OLD_FILES+=usr/share/terminfo/p/prism4 OLD_FILES+=usr/share/terminfo/p/prism5 OLD_FILES+=usr/share/terminfo/p/prism7 OLD_FILES+=usr/share/terminfo/p/prism8 OLD_FILES+=usr/share/terminfo/p/prism8-w OLD_FILES+=usr/share/terminfo/p/prism8gl OLD_FILES+=usr/share/terminfo/p/prism9 OLD_FILES+=usr/share/terminfo/p/prism9-8 OLD_FILES+=usr/share/terminfo/p/prism9-8-w OLD_FILES+=usr/share/terminfo/p/prism9-w OLD_FILES+=usr/share/terminfo/p/pro350 OLD_FILES+=usr/share/terminfo/p/ps300 OLD_FILES+=usr/share/terminfo/p/psterm OLD_FILES+=usr/share/terminfo/p/psterm-80x24 OLD_FILES+=usr/share/terminfo/p/psterm-90x28 OLD_FILES+=usr/share/terminfo/p/psterm-96x48 OLD_FILES+=usr/share/terminfo/p/psterm-basic OLD_FILES+=usr/share/terminfo/p/psterm-fast OLD_FILES+=usr/share/terminfo/p/psx_ansi OLD_FILES+=usr/share/terminfo/p/pt100 OLD_FILES+=usr/share/terminfo/p/pt100w OLD_FILES+=usr/share/terminfo/p/pt200 OLD_FILES+=usr/share/terminfo/p/pt200w OLD_FILES+=usr/share/terminfo/p/pt210 OLD_FILES+=usr/share/terminfo/p/pt250 OLD_FILES+=usr/share/terminfo/p/pt250w OLD_FILES+=usr/share/terminfo/p/pt505 OLD_FILES+=usr/share/terminfo/p/pt505-22 OLD_FILES+=usr/share/terminfo/p/pt505-24 OLD_FILES+=usr/share/terminfo/p/pty OLD_FILES+=usr/share/terminfo/p/putty OLD_FILES+=usr/share/terminfo/p/putty+fnkeys OLD_FILES+=usr/share/terminfo/p/putty+fnkeys+esc OLD_FILES+=usr/share/terminfo/p/putty+fnkeys+linux OLD_FILES+=usr/share/terminfo/p/putty+fnkeys+sco OLD_FILES+=usr/share/terminfo/p/putty+fnkeys+vt100 OLD_FILES+=usr/share/terminfo/p/putty+fnkeys+vt400 OLD_FILES+=usr/share/terminfo/p/putty+fnkeys+xterm OLD_FILES+=usr/share/terminfo/p/putty+keypad OLD_FILES+=usr/share/terminfo/p/putty+screen OLD_FILES+=usr/share/terminfo/p/putty-256color OLD_FILES+=usr/share/terminfo/p/putty-m1 OLD_FILES+=usr/share/terminfo/p/putty-m1b OLD_FILES+=usr/share/terminfo/p/putty-m2 OLD_FILES+=usr/share/terminfo/p/putty-noapp OLD_FILES+=usr/share/terminfo/p/putty-sco OLD_FILES+=usr/share/terminfo/p/putty-screen OLD_FILES+=usr/share/terminfo/p/putty-vt100 OLD_DIRS+=usr/share/terminfo/p/ OLD_FILES+=usr/share/terminfo/q/qansi OLD_FILES+=usr/share/terminfo/q/qansi-g OLD_FILES+=usr/share/terminfo/q/qansi-m OLD_FILES+=usr/share/terminfo/q/qansi-t OLD_FILES+=usr/share/terminfo/q/qansi-w OLD_FILES+=usr/share/terminfo/q/qdcons OLD_FILES+=usr/share/terminfo/q/qdss OLD_FILES+=usr/share/terminfo/q/qnx OLD_FILES+=usr/share/terminfo/q/qnx4 OLD_FILES+=usr/share/terminfo/q/qnxm OLD_FILES+=usr/share/terminfo/q/qnxt OLD_FILES+=usr/share/terminfo/q/qnxt2 OLD_FILES+=usr/share/terminfo/q/qnxt4 OLD_FILES+=usr/share/terminfo/q/qnxtmono OLD_FILES+=usr/share/terminfo/q/qnxw OLD_FILES+=usr/share/terminfo/q/qume OLD_FILES+=usr/share/terminfo/q/qume5 OLD_FILES+=usr/share/terminfo/q/qvt101 OLD_FILES+=usr/share/terminfo/q/qvt101+ OLD_FILES+=usr/share/terminfo/q/qvt101p OLD_FILES+=usr/share/terminfo/q/qvt102 OLD_FILES+=usr/share/terminfo/q/qvt103 OLD_FILES+=usr/share/terminfo/q/qvt103-w OLD_FILES+=usr/share/terminfo/q/qvt108 OLD_FILES+=usr/share/terminfo/q/qvt119 OLD_FILES+=usr/share/terminfo/q/qvt119+ OLD_FILES+=usr/share/terminfo/q/qvt119+-25 OLD_FILES+=usr/share/terminfo/q/qvt119+-25-w OLD_FILES+=usr/share/terminfo/q/qvt119+-w OLD_FILES+=usr/share/terminfo/q/qvt119-25-w OLD_FILES+=usr/share/terminfo/q/qvt119-w OLD_FILES+=usr/share/terminfo/q/qvt119p OLD_FILES+=usr/share/terminfo/q/qvt119p-25 OLD_FILES+=usr/share/terminfo/q/qvt119p-25-w OLD_FILES+=usr/share/terminfo/q/qvt119p-w OLD_FILES+=usr/share/terminfo/q/qvt203 OLD_FILES+=usr/share/terminfo/q/qvt203+ OLD_FILES+=usr/share/terminfo/q/qvt203-25 OLD_FILES+=usr/share/terminfo/q/qvt203-25-w OLD_FILES+=usr/share/terminfo/q/qvt203-w OLD_FILES+=usr/share/terminfo/q/qvt203-w-am OLD_DIRS+=usr/share/terminfo/q/ OLD_FILES+=usr/share/terminfo/r/rbcomm OLD_FILES+=usr/share/terminfo/r/rbcomm-nam OLD_FILES+=usr/share/terminfo/r/rbcomm-w OLD_FILES+=usr/share/terminfo/r/rca OLD_FILES+=usr/share/terminfo/r/rcons OLD_FILES+=usr/share/terminfo/r/rcons-color OLD_FILES+=usr/share/terminfo/r/rebus3180 OLD_FILES+=usr/share/terminfo/r/regent OLD_FILES+=usr/share/terminfo/r/regent100 OLD_FILES+=usr/share/terminfo/r/regent20 OLD_FILES+=usr/share/terminfo/r/regent200 OLD_FILES+=usr/share/terminfo/r/regent25 OLD_FILES+=usr/share/terminfo/r/regent40 OLD_FILES+=usr/share/terminfo/r/regent40+ OLD_FILES+=usr/share/terminfo/r/regent60 OLD_FILES+=usr/share/terminfo/r/rt6221 OLD_FILES+=usr/share/terminfo/r/rt6221-w OLD_FILES+=usr/share/terminfo/r/rtpc OLD_FILES+=usr/share/terminfo/r/rxvt OLD_FILES+=usr/share/terminfo/r/rxvt+pcfkeys OLD_FILES+=usr/share/terminfo/r/rxvt-16color OLD_FILES+=usr/share/terminfo/r/rxvt-256color OLD_FILES+=usr/share/terminfo/r/rxvt-88color OLD_FILES+=usr/share/terminfo/r/rxvt-basic OLD_FILES+=usr/share/terminfo/r/rxvt-color OLD_FILES+=usr/share/terminfo/r/rxvt-cygwin OLD_FILES+=usr/share/terminfo/r/rxvt-cygwin-native OLD_FILES+=usr/share/terminfo/r/rxvt-xpm OLD_DIRS+=usr/share/terminfo/r/ OLD_FILES+=usr/share/terminfo/s/s4 OLD_FILES+=usr/share/terminfo/s/sb1 OLD_FILES+=usr/share/terminfo/s/sb2 OLD_FILES+=usr/share/terminfo/s/sb3 OLD_FILES+=usr/share/terminfo/s/sbi OLD_FILES+=usr/share/terminfo/s/sbobcat OLD_FILES+=usr/share/terminfo/s/sc410 OLD_FILES+=usr/share/terminfo/s/sc415 OLD_FILES+=usr/share/terminfo/s/scanset OLD_FILES+=usr/share/terminfo/s/scoansi OLD_FILES+=usr/share/terminfo/s/scoansi-new OLD_FILES+=usr/share/terminfo/s/scoansi-old OLD_FILES+=usr/share/terminfo/s/screen OLD_FILES+=usr/share/terminfo/s/screen+fkeys OLD_FILES+=usr/share/terminfo/s/screen+italics OLD_FILES+=usr/share/terminfo/s/screen-16color OLD_FILES+=usr/share/terminfo/s/screen-16color-bce OLD_FILES+=usr/share/terminfo/s/screen-16color-bce-s OLD_FILES+=usr/share/terminfo/s/screen-16color-s OLD_FILES+=usr/share/terminfo/s/screen-256color OLD_FILES+=usr/share/terminfo/s/screen-256color-bce OLD_FILES+=usr/share/terminfo/s/screen-256color-bce-s OLD_FILES+=usr/share/terminfo/s/screen-256color-s OLD_FILES+=usr/share/terminfo/s/screen-bce OLD_FILES+=usr/share/terminfo/s/screen-bce.Eterm OLD_FILES+=usr/share/terminfo/s/screen-bce.gnome OLD_FILES+=usr/share/terminfo/s/screen-bce.konsole OLD_FILES+=usr/share/terminfo/s/screen-bce.linux OLD_FILES+=usr/share/terminfo/s/screen-bce.mrxvt OLD_FILES+=usr/share/terminfo/s/screen-bce.rxvt OLD_FILES+=usr/share/terminfo/s/screen-bce.xterm-new OLD_FILES+=usr/share/terminfo/s/screen-s OLD_FILES+=usr/share/terminfo/s/screen-w OLD_FILES+=usr/share/terminfo/s/screen.Eterm OLD_FILES+=usr/share/terminfo/s/screen.gnome OLD_FILES+=usr/share/terminfo/s/screen.konsole OLD_FILES+=usr/share/terminfo/s/screen.konsole-256color OLD_FILES+=usr/share/terminfo/s/screen.linux OLD_FILES+=usr/share/terminfo/s/screen.linux-m1 OLD_FILES+=usr/share/terminfo/s/screen.linux-m1b OLD_FILES+=usr/share/terminfo/s/screen.linux-m2 OLD_FILES+=usr/share/terminfo/s/screen.linux-s OLD_FILES+=usr/share/terminfo/s/screen.minitel1 OLD_FILES+=usr/share/terminfo/s/screen.minitel1-nb OLD_FILES+=usr/share/terminfo/s/screen.minitel12-80 OLD_FILES+=usr/share/terminfo/s/screen.minitel1b OLD_FILES+=usr/share/terminfo/s/screen.minitel1b-80 OLD_FILES+=usr/share/terminfo/s/screen.minitel1b-nb OLD_FILES+=usr/share/terminfo/s/screen.minitel2-80 OLD_FILES+=usr/share/terminfo/s/screen.mlterm OLD_FILES+=usr/share/terminfo/s/screen.mlterm-256color OLD_FILES+=usr/share/terminfo/s/screen.mrxvt OLD_FILES+=usr/share/terminfo/s/screen.putty OLD_FILES+=usr/share/terminfo/s/screen.putty-256color OLD_FILES+=usr/share/terminfo/s/screen.putty-m1 OLD_FILES+=usr/share/terminfo/s/screen.putty-m1b OLD_FILES+=usr/share/terminfo/s/screen.putty-m2 OLD_FILES+=usr/share/terminfo/s/screen.rxvt OLD_FILES+=usr/share/terminfo/s/screen.teraterm OLD_FILES+=usr/share/terminfo/s/screen.vte OLD_FILES+=usr/share/terminfo/s/screen.vte-256color OLD_FILES+=usr/share/terminfo/s/screen.xterm-256color OLD_FILES+=usr/share/terminfo/s/screen.xterm-new OLD_FILES+=usr/share/terminfo/s/screen.xterm-r6 OLD_FILES+=usr/share/terminfo/s/screen.xterm-xfree86 OLD_FILES+=usr/share/terminfo/s/screen2 OLD_FILES+=usr/share/terminfo/s/screen3 OLD_FILES+=usr/share/terminfo/s/screen4 OLD_FILES+=usr/share/terminfo/s/screen5 OLD_FILES+=usr/share/terminfo/s/screwpoint OLD_FILES+=usr/share/terminfo/s/scrhp OLD_FILES+=usr/share/terminfo/s/scrt OLD_FILES+=usr/share/terminfo/s/securecrt OLD_FILES+=usr/share/terminfo/s/sibo OLD_FILES+=usr/share/terminfo/s/simpleterm OLD_FILES+=usr/share/terminfo/s/simterm OLD_FILES+=usr/share/terminfo/s/soroc OLD_FILES+=usr/share/terminfo/s/soroc120 OLD_FILES+=usr/share/terminfo/s/soroc140 OLD_FILES+=usr/share/terminfo/s/spinwriter OLD_FILES+=usr/share/terminfo/s/st OLD_FILES+=usr/share/terminfo/s/st-0.6 OLD_FILES+=usr/share/terminfo/s/st-0.7 OLD_FILES+=usr/share/terminfo/s/st-0.8 OLD_FILES+=usr/share/terminfo/s/st-16color OLD_FILES+=usr/share/terminfo/s/st-256color OLD_FILES+=usr/share/terminfo/s/st-direct OLD_FILES+=usr/share/terminfo/s/st52 OLD_FILES+=usr/share/terminfo/s/st52-color OLD_FILES+=usr/share/terminfo/s/st52-m OLD_FILES+=usr/share/terminfo/s/st52-old OLD_FILES+=usr/share/terminfo/s/stterm OLD_FILES+=usr/share/terminfo/s/stterm-16color OLD_FILES+=usr/share/terminfo/s/stterm-256color OLD_FILES+=usr/share/terminfo/s/stv52 OLD_FILES+=usr/share/terminfo/s/stv52pc OLD_FILES+=usr/share/terminfo/s/sun OLD_FILES+=usr/share/terminfo/s/sun+sl OLD_FILES+=usr/share/terminfo/s/sun-1 OLD_FILES+=usr/share/terminfo/s/sun-12 OLD_FILES+=usr/share/terminfo/s/sun-17 OLD_FILES+=usr/share/terminfo/s/sun-24 OLD_FILES+=usr/share/terminfo/s/sun-34 OLD_FILES+=usr/share/terminfo/s/sun-48 OLD_FILES+=usr/share/terminfo/s/sun-c OLD_FILES+=usr/share/terminfo/s/sun-cgsix OLD_FILES+=usr/share/terminfo/s/sun-cmd OLD_FILES+=usr/share/terminfo/s/sun-color OLD_FILES+=usr/share/terminfo/s/sun-e OLD_FILES+=usr/share/terminfo/s/sun-e-s OLD_FILES+=usr/share/terminfo/s/sun-il OLD_FILES+=usr/share/terminfo/s/sun-nic OLD_FILES+=usr/share/terminfo/s/sun-s OLD_FILES+=usr/share/terminfo/s/sun-s-e OLD_FILES+=usr/share/terminfo/s/sun-ss5 OLD_FILES+=usr/share/terminfo/s/sun-type4 OLD_FILES+=usr/share/terminfo/s/sun1 OLD_FILES+=usr/share/terminfo/s/sun2 OLD_FILES+=usr/share/terminfo/s/sune OLD_FILES+=usr/share/terminfo/s/superbee OLD_FILES+=usr/share/terminfo/s/superbee-xsb OLD_FILES+=usr/share/terminfo/s/superbeeic OLD_FILES+=usr/share/terminfo/s/superbrain OLD_FILES+=usr/share/terminfo/s/sv80 OLD_FILES+=usr/share/terminfo/s/swtp OLD_FILES+=usr/share/terminfo/s/synertek OLD_FILES+=usr/share/terminfo/s/synertek380 OLD_FILES+=usr/share/terminfo/s/system1 OLD_DIRS+=usr/share/terminfo/s/ OLD_FILES+=usr/share/terminfo/t/t10 OLD_FILES+=usr/share/terminfo/t/t1061 OLD_FILES+=usr/share/terminfo/t/t1061f OLD_FILES+=usr/share/terminfo/t/t16 OLD_FILES+=usr/share/terminfo/t/t3700 OLD_FILES+=usr/share/terminfo/t/t3800 OLD_FILES+=usr/share/terminfo/t/t653x OLD_FILES+=usr/share/terminfo/t/tab OLD_FILES+=usr/share/terminfo/t/tab132 OLD_FILES+=usr/share/terminfo/t/tab132-15 OLD_FILES+=usr/share/terminfo/t/tab132-rv OLD_FILES+=usr/share/terminfo/t/tab132-w OLD_FILES+=usr/share/terminfo/t/tab132-w-rv OLD_FILES+=usr/share/terminfo/t/tandem6510 OLD_FILES+=usr/share/terminfo/t/tandem653 OLD_FILES+=usr/share/terminfo/t/tek OLD_FILES+=usr/share/terminfo/t/tek4012 OLD_FILES+=usr/share/terminfo/t/tek4013 OLD_FILES+=usr/share/terminfo/t/tek4014 OLD_FILES+=usr/share/terminfo/t/tek4014-sm OLD_FILES+=usr/share/terminfo/t/tek4015 OLD_FILES+=usr/share/terminfo/t/tek4015-sm OLD_FILES+=usr/share/terminfo/t/tek4023 OLD_FILES+=usr/share/terminfo/t/tek4024 OLD_FILES+=usr/share/terminfo/t/tek4025 OLD_FILES+=usr/share/terminfo/t/tek4025-17 OLD_FILES+=usr/share/terminfo/t/tek4025-17-ws OLD_FILES+=usr/share/terminfo/t/tek4025-cr OLD_FILES+=usr/share/terminfo/t/tek4025-ex OLD_FILES+=usr/share/terminfo/t/tek4025a OLD_FILES+=usr/share/terminfo/t/tek4025ex OLD_FILES+=usr/share/terminfo/t/tek4027 OLD_FILES+=usr/share/terminfo/t/tek4027-ex OLD_FILES+=usr/share/terminfo/t/tek4105 OLD_FILES+=usr/share/terminfo/t/tek4105-30 OLD_FILES+=usr/share/terminfo/t/tek4105a OLD_FILES+=usr/share/terminfo/t/tek4106brl OLD_FILES+=usr/share/terminfo/t/tek4107 OLD_FILES+=usr/share/terminfo/t/tek4107brl OLD_FILES+=usr/share/terminfo/t/tek4109 OLD_FILES+=usr/share/terminfo/t/tek4109brl OLD_FILES+=usr/share/terminfo/t/tek4112 OLD_FILES+=usr/share/terminfo/t/tek4112-5 OLD_FILES+=usr/share/terminfo/t/tek4112-nd OLD_FILES+=usr/share/terminfo/t/tek4113 OLD_FILES+=usr/share/terminfo/t/tek4113-34 OLD_FILES+=usr/share/terminfo/t/tek4113-nd OLD_FILES+=usr/share/terminfo/t/tek4114 OLD_FILES+=usr/share/terminfo/t/tek4115 OLD_FILES+=usr/share/terminfo/t/tek4125 OLD_FILES+=usr/share/terminfo/t/tek4205 OLD_FILES+=usr/share/terminfo/t/tek4207 OLD_FILES+=usr/share/terminfo/t/tek4207-s OLD_FILES+=usr/share/terminfo/t/tek4404 OLD_FILES+=usr/share/terminfo/t/teken OLD_FILES+=usr/share/terminfo/t/teleray OLD_FILES+=usr/share/terminfo/t/teletec OLD_FILES+=usr/share/terminfo/t/teraterm OLD_FILES+=usr/share/terminfo/t/teraterm-256color OLD_FILES+=usr/share/terminfo/t/teraterm2.3 OLD_FILES+=usr/share/terminfo/t/teraterm4.59 OLD_FILES+=usr/share/terminfo/t/teraterm4.97 OLD_FILES+=usr/share/terminfo/t/terminator OLD_FILES+=usr/share/terminfo/t/terminet OLD_FILES+=usr/share/terminfo/t/terminet1200 OLD_FILES+=usr/share/terminfo/t/terminet300 OLD_FILES+=usr/share/terminfo/t/terminology OLD_FILES+=usr/share/terminfo/t/terminology-0.6.1 OLD_FILES+=usr/share/terminfo/t/terminology-1.0.0 OLD_FILES+=usr/share/terminfo/t/terminology-1.8.1 OLD_FILES+=usr/share/terminfo/t/termite OLD_FILES+=usr/share/terminfo/t/tgtelnet OLD_FILES+=usr/share/terminfo/t/ti700 OLD_FILES+=usr/share/terminfo/t/ti703 OLD_FILES+=usr/share/terminfo/t/ti703-w OLD_FILES+=usr/share/terminfo/t/ti707 OLD_FILES+=usr/share/terminfo/t/ti707-w OLD_FILES+=usr/share/terminfo/t/ti733 OLD_FILES+=usr/share/terminfo/t/ti735 OLD_FILES+=usr/share/terminfo/t/ti745 OLD_FILES+=usr/share/terminfo/t/ti800 OLD_FILES+=usr/share/terminfo/t/ti916 OLD_FILES+=usr/share/terminfo/t/ti916-132 OLD_FILES+=usr/share/terminfo/t/ti916-220-7 OLD_FILES+=usr/share/terminfo/t/ti916-220-8 OLD_FILES+=usr/share/terminfo/t/ti916-8 OLD_FILES+=usr/share/terminfo/t/ti916-8-132 OLD_FILES+=usr/share/terminfo/t/ti924 OLD_FILES+=usr/share/terminfo/t/ti924-8 OLD_FILES+=usr/share/terminfo/t/ti924-8w OLD_FILES+=usr/share/terminfo/t/ti924w OLD_FILES+=usr/share/terminfo/t/ti926 OLD_FILES+=usr/share/terminfo/t/ti926-8 OLD_FILES+=usr/share/terminfo/t/ti928 OLD_FILES+=usr/share/terminfo/t/ti928-8 OLD_FILES+=usr/share/terminfo/t/ti931 OLD_FILES+=usr/share/terminfo/t/ti_ansi OLD_FILES+=usr/share/terminfo/t/tkterm OLD_FILES+=usr/share/terminfo/t/tmux OLD_FILES+=usr/share/terminfo/t/tmux-256color OLD_FILES+=usr/share/terminfo/t/tmux-direct OLD_FILES+=usr/share/terminfo/t/tn1200 OLD_FILES+=usr/share/terminfo/t/tn300 OLD_FILES+=usr/share/terminfo/t/trs16 OLD_FILES+=usr/share/terminfo/t/trs2 OLD_FILES+=usr/share/terminfo/t/trs80II OLD_FILES+=usr/share/terminfo/t/trsII OLD_FILES+=usr/share/terminfo/t/ts-1 OLD_FILES+=usr/share/terminfo/t/ts-1p OLD_FILES+=usr/share/terminfo/t/ts1 OLD_FILES+=usr/share/terminfo/t/ts100 OLD_FILES+=usr/share/terminfo/t/ts100-ctxt OLD_FILES+=usr/share/terminfo/t/ts100-sp OLD_FILES+=usr/share/terminfo/t/ts1p OLD_FILES+=usr/share/terminfo/t/tt OLD_FILES+=usr/share/terminfo/t/tt505-22 OLD_FILES+=usr/share/terminfo/t/tt52 OLD_FILES+=usr/share/terminfo/t/tty33 OLD_FILES+=usr/share/terminfo/t/tty35 OLD_FILES+=usr/share/terminfo/t/tty37 OLD_FILES+=usr/share/terminfo/t/tty40 OLD_FILES+=usr/share/terminfo/t/tty43 OLD_FILES+=usr/share/terminfo/t/tty4420 OLD_FILES+=usr/share/terminfo/t/tty4424 OLD_FILES+=usr/share/terminfo/t/tty4424-1 OLD_FILES+=usr/share/terminfo/t/tty4424m OLD_FILES+=usr/share/terminfo/t/tty4426 OLD_FILES+=usr/share/terminfo/t/tty5410 OLD_FILES+=usr/share/terminfo/t/tty5410-w OLD_FILES+=usr/share/terminfo/t/tty5410v1 OLD_FILES+=usr/share/terminfo/t/tty5410v1-w OLD_FILES+=usr/share/terminfo/t/tty5420 OLD_FILES+=usr/share/terminfo/t/tty5420+nl OLD_FILES+=usr/share/terminfo/t/tty5420-nl OLD_FILES+=usr/share/terminfo/t/tty5420-rv OLD_FILES+=usr/share/terminfo/t/tty5420-rv-nl OLD_FILES+=usr/share/terminfo/t/tty5420-w OLD_FILES+=usr/share/terminfo/t/tty5420-w-nl OLD_FILES+=usr/share/terminfo/t/tty5420-w-rv OLD_FILES+=usr/share/terminfo/t/tty5420-w-rv-n OLD_FILES+=usr/share/terminfo/t/tty5425 OLD_FILES+=usr/share/terminfo/t/tty5425-nl OLD_FILES+=usr/share/terminfo/t/tty5425-w OLD_FILES+=usr/share/terminfo/t/tty5620 OLD_FILES+=usr/share/terminfo/t/tty5620-1 OLD_FILES+=usr/share/terminfo/t/tty5620-24 OLD_FILES+=usr/share/terminfo/t/tty5620-34 OLD_FILES+=usr/share/terminfo/t/tty5620-s OLD_FILES+=usr/share/terminfo/t/ttydmd OLD_FILES+=usr/share/terminfo/t/tvi803 OLD_FILES+=usr/share/terminfo/t/tvi9065 OLD_FILES+=usr/share/terminfo/t/tvi910 OLD_FILES+=usr/share/terminfo/t/tvi910+ OLD_FILES+=usr/share/terminfo/t/tvi912 OLD_FILES+=usr/share/terminfo/t/tvi912b OLD_FILES+=usr/share/terminfo/t/tvi912b+2p OLD_FILES+=usr/share/terminfo/t/tvi912b+dim OLD_FILES+=usr/share/terminfo/t/tvi912b+mc OLD_FILES+=usr/share/terminfo/t/tvi912b+printer OLD_FILES+=usr/share/terminfo/t/tvi912b+vb OLD_FILES+=usr/share/terminfo/t/tvi912b-2p OLD_FILES+=usr/share/terminfo/t/tvi912b-2p-mc OLD_FILES+=usr/share/terminfo/t/tvi912b-2p-p OLD_FILES+=usr/share/terminfo/t/tvi912b-2p-unk OLD_FILES+=usr/share/terminfo/t/tvi912b-mc OLD_FILES+=usr/share/terminfo/t/tvi912b-mc-2p OLD_FILES+=usr/share/terminfo/t/tvi912b-mc-vb OLD_FILES+=usr/share/terminfo/t/tvi912b-p OLD_FILES+=usr/share/terminfo/t/tvi912b-p-2p OLD_FILES+=usr/share/terminfo/t/tvi912b-p-vb OLD_FILES+=usr/share/terminfo/t/tvi912b-unk OLD_FILES+=usr/share/terminfo/t/tvi912b-unk-2p OLD_FILES+=usr/share/terminfo/t/tvi912b-unk-vb OLD_FILES+=usr/share/terminfo/t/tvi912b-vb OLD_FILES+=usr/share/terminfo/t/tvi912b-vb-mc OLD_FILES+=usr/share/terminfo/t/tvi912b-vb-p OLD_FILES+=usr/share/terminfo/t/tvi912b-vb-unk OLD_FILES+=usr/share/terminfo/t/tvi912c OLD_FILES+=usr/share/terminfo/t/tvi912c-2p OLD_FILES+=usr/share/terminfo/t/tvi912c-2p-mc OLD_FILES+=usr/share/terminfo/t/tvi912c-2p-p OLD_FILES+=usr/share/terminfo/t/tvi912c-2p-unk OLD_FILES+=usr/share/terminfo/t/tvi912c-mc OLD_FILES+=usr/share/terminfo/t/tvi912c-mc-2p OLD_FILES+=usr/share/terminfo/t/tvi912c-mc-vb OLD_FILES+=usr/share/terminfo/t/tvi912c-p OLD_FILES+=usr/share/terminfo/t/tvi912c-p-2p OLD_FILES+=usr/share/terminfo/t/tvi912c-p-vb OLD_FILES+=usr/share/terminfo/t/tvi912c-unk OLD_FILES+=usr/share/terminfo/t/tvi912c-unk-2p OLD_FILES+=usr/share/terminfo/t/tvi912c-unk-vb OLD_FILES+=usr/share/terminfo/t/tvi912c-vb OLD_FILES+=usr/share/terminfo/t/tvi912c-vb-mc OLD_FILES+=usr/share/terminfo/t/tvi912c-vb-p OLD_FILES+=usr/share/terminfo/t/tvi912c-vb-unk OLD_FILES+=usr/share/terminfo/t/tvi912cc OLD_FILES+=usr/share/terminfo/t/tvi914 OLD_FILES+=usr/share/terminfo/t/tvi920 OLD_FILES+=usr/share/terminfo/t/tvi920b OLD_FILES+=usr/share/terminfo/t/tvi920b+fn OLD_FILES+=usr/share/terminfo/t/tvi920b-2p OLD_FILES+=usr/share/terminfo/t/tvi920b-2p-mc OLD_FILES+=usr/share/terminfo/t/tvi920b-2p-p OLD_FILES+=usr/share/terminfo/t/tvi920b-2p-unk OLD_FILES+=usr/share/terminfo/t/tvi920b-mc OLD_FILES+=usr/share/terminfo/t/tvi920b-mc-2p OLD_FILES+=usr/share/terminfo/t/tvi920b-mc-vb OLD_FILES+=usr/share/terminfo/t/tvi920b-p OLD_FILES+=usr/share/terminfo/t/tvi920b-p-2p OLD_FILES+=usr/share/terminfo/t/tvi920b-p-vb OLD_FILES+=usr/share/terminfo/t/tvi920b-unk OLD_FILES+=usr/share/terminfo/t/tvi920b-unk-2p OLD_FILES+=usr/share/terminfo/t/tvi920b-unk-vb OLD_FILES+=usr/share/terminfo/t/tvi920b-vb OLD_FILES+=usr/share/terminfo/t/tvi920b-vb-mc OLD_FILES+=usr/share/terminfo/t/tvi920b-vb-p OLD_FILES+=usr/share/terminfo/t/tvi920b-vb-unk OLD_FILES+=usr/share/terminfo/t/tvi920c OLD_FILES+=usr/share/terminfo/t/tvi920c-2p OLD_FILES+=usr/share/terminfo/t/tvi920c-2p-mc OLD_FILES+=usr/share/terminfo/t/tvi920c-2p-p OLD_FILES+=usr/share/terminfo/t/tvi920c-2p-unk OLD_FILES+=usr/share/terminfo/t/tvi920c-mc OLD_FILES+=usr/share/terminfo/t/tvi920c-mc-2p OLD_FILES+=usr/share/terminfo/t/tvi920c-mc-vb OLD_FILES+=usr/share/terminfo/t/tvi920c-p OLD_FILES+=usr/share/terminfo/t/tvi920c-p-2p OLD_FILES+=usr/share/terminfo/t/tvi920c-p-vb OLD_FILES+=usr/share/terminfo/t/tvi920c-unk OLD_FILES+=usr/share/terminfo/t/tvi920c-unk-2p OLD_FILES+=usr/share/terminfo/t/tvi920c-unk-vb OLD_FILES+=usr/share/terminfo/t/tvi920c-vb OLD_FILES+=usr/share/terminfo/t/tvi920c-vb-mc OLD_FILES+=usr/share/terminfo/t/tvi920c-vb-p OLD_FILES+=usr/share/terminfo/t/tvi920c-vb-unk OLD_FILES+=usr/share/terminfo/t/tvi921 OLD_FILES+=usr/share/terminfo/t/tvi924 OLD_FILES+=usr/share/terminfo/t/tvi925 OLD_FILES+=usr/share/terminfo/t/tvi925-hi OLD_FILES+=usr/share/terminfo/t/tvi92B OLD_FILES+=usr/share/terminfo/t/tvi92D OLD_FILES+=usr/share/terminfo/t/tvi950 OLD_FILES+=usr/share/terminfo/t/tvi950-2p OLD_FILES+=usr/share/terminfo/t/tvi950-4p OLD_FILES+=usr/share/terminfo/t/tvi950-rv OLD_FILES+=usr/share/terminfo/t/tvi950-rv-2p OLD_FILES+=usr/share/terminfo/t/tvi950-rv-4p OLD_FILES+=usr/share/terminfo/t/tvi955 OLD_FILES+=usr/share/terminfo/t/tvi955-hb OLD_FILES+=usr/share/terminfo/t/tvi955-w OLD_FILES+=usr/share/terminfo/t/tvi970 OLD_FILES+=usr/share/terminfo/t/tvi970-2p OLD_FILES+=usr/share/terminfo/t/tvi970-vb OLD_FILES+=usr/share/terminfo/t/tvipt OLD_FILES+=usr/share/terminfo/t/tw100 OLD_FILES+=usr/share/terminfo/t/tw52 OLD_FILES+=usr/share/terminfo/t/tw52-color OLD_FILES+=usr/share/terminfo/t/tw52-m OLD_FILES+=usr/share/terminfo/t/tws-generic OLD_FILES+=usr/share/terminfo/t/tws2102-sna OLD_FILES+=usr/share/terminfo/t/tws2103 OLD_FILES+=usr/share/terminfo/t/tws2103-sna OLD_DIRS+=usr/share/terminfo/t/ OLD_FILES+=usr/share/terminfo/u/ultima2 OLD_FILES+=usr/share/terminfo/u/ultimaII OLD_FILES+=usr/share/terminfo/u/uniterm OLD_FILES+=usr/share/terminfo/u/uniterm49 OLD_FILES+=usr/share/terminfo/u/unixpc OLD_FILES+=usr/share/terminfo/u/unknown OLD_FILES+=usr/share/terminfo/u/uts30 OLD_FILES+=usr/share/terminfo/u/uwin OLD_DIRS+=usr/share/terminfo/u/ OLD_FILES+=usr/share/terminfo/v/v200-nam OLD_FILES+=usr/share/terminfo/v/v320n OLD_FILES+=usr/share/terminfo/v/v3220 OLD_FILES+=usr/share/terminfo/v/v5410 OLD_FILES+=usr/share/terminfo/v/vanilla OLD_FILES+=usr/share/terminfo/v/vapple OLD_FILES+=usr/share/terminfo/v/vc103 OLD_FILES+=usr/share/terminfo/v/vc203 OLD_FILES+=usr/share/terminfo/v/vc303 OLD_FILES+=usr/share/terminfo/v/vc303a OLD_FILES+=usr/share/terminfo/v/vc403a OLD_FILES+=usr/share/terminfo/v/vc404 OLD_FILES+=usr/share/terminfo/v/vc404-s OLD_FILES+=usr/share/terminfo/v/vc414 OLD_FILES+=usr/share/terminfo/v/vc414h OLD_FILES+=usr/share/terminfo/v/vc415 OLD_FILES+=usr/share/terminfo/v/venix OLD_FILES+=usr/share/terminfo/v/versaterm OLD_FILES+=usr/share/terminfo/v/vi200 OLD_FILES+=usr/share/terminfo/v/vi200-f OLD_FILES+=usr/share/terminfo/v/vi200-rv OLD_FILES+=usr/share/terminfo/v/vi300 OLD_FILES+=usr/share/terminfo/v/vi300-old OLD_FILES+=usr/share/terminfo/v/vi50 OLD_FILES+=usr/share/terminfo/v/vi500 OLD_FILES+=usr/share/terminfo/v/vi50adm OLD_FILES+=usr/share/terminfo/v/vi55 OLD_FILES+=usr/share/terminfo/v/vi550 OLD_FILES+=usr/share/terminfo/v/vi603 OLD_FILES+=usr/share/terminfo/v/viewdata OLD_FILES+=usr/share/terminfo/v/viewdata-o OLD_FILES+=usr/share/terminfo/v/viewdata-rv OLD_FILES+=usr/share/terminfo/v/viewpoint OLD_FILES+=usr/share/terminfo/v/viewpoint3a+ OLD_FILES+=usr/share/terminfo/v/viewpoint60 OLD_FILES+=usr/share/terminfo/v/viewpoint90 OLD_FILES+=usr/share/terminfo/v/vip OLD_FILES+=usr/share/terminfo/v/vip-H OLD_FILES+=usr/share/terminfo/v/vip-Hw OLD_FILES+=usr/share/terminfo/v/vip-w OLD_FILES+=usr/share/terminfo/v/vip7800-H OLD_FILES+=usr/share/terminfo/v/vip7800-Hw OLD_FILES+=usr/share/terminfo/v/vip7800-w OLD_FILES+=usr/share/terminfo/v/visa50 OLD_FILES+=usr/share/terminfo/v/visual603 OLD_FILES+=usr/share/terminfo/v/vitty OLD_FILES+=usr/share/terminfo/v/vk100 OLD_FILES+=usr/share/terminfo/v/vp3a+ OLD_FILES+=usr/share/terminfo/v/vp60 OLD_FILES+=usr/share/terminfo/v/vp90 OLD_FILES+=usr/share/terminfo/v/vremote OLD_FILES+=usr/share/terminfo/v/vs100 OLD_FILES+=usr/share/terminfo/v/vs100-x10 OLD_FILES+=usr/share/terminfo/v/vsc OLD_FILES+=usr/share/terminfo/v/vscode OLD_FILES+=usr/share/terminfo/v/vscode-direct OLD_FILES+=usr/share/terminfo/v/vt-61 OLD_FILES+=usr/share/terminfo/v/vt-utf8 OLD_FILES+=usr/share/terminfo/v/vt100 OLD_FILES+=usr/share/terminfo/v/vt100+ OLD_FILES+=usr/share/terminfo/v/vt100+4bsd OLD_FILES+=usr/share/terminfo/v/vt100+enq OLD_FILES+=usr/share/terminfo/v/vt100+fnkeys OLD_FILES+=usr/share/terminfo/v/vt100+keypad OLD_FILES+=usr/share/terminfo/v/vt100+pfkeys OLD_FILES+=usr/share/terminfo/v/vt100-am OLD_FILES+=usr/share/terminfo/v/vt100-bm OLD_FILES+=usr/share/terminfo/v/vt100-bm-o OLD_FILES+=usr/share/terminfo/v/vt100-bot-s OLD_FILES+=usr/share/terminfo/v/vt100-nam OLD_FILES+=usr/share/terminfo/v/vt100-nam-w OLD_FILES+=usr/share/terminfo/v/vt100-nav OLD_FILES+=usr/share/terminfo/v/vt100-nav-w OLD_FILES+=usr/share/terminfo/v/vt100-putty OLD_FILES+=usr/share/terminfo/v/vt100-s OLD_FILES+=usr/share/terminfo/v/vt100-s-bot OLD_FILES+=usr/share/terminfo/v/vt100-s-top OLD_FILES+=usr/share/terminfo/v/vt100-top-s OLD_FILES+=usr/share/terminfo/v/vt100-vb OLD_FILES+=usr/share/terminfo/v/vt100-w OLD_FILES+=usr/share/terminfo/v/vt100-w-am OLD_FILES+=usr/share/terminfo/v/vt100-w-nam OLD_FILES+=usr/share/terminfo/v/vt100-w-nav OLD_FILES+=usr/share/terminfo/v/vt100nam OLD_FILES+=usr/share/terminfo/v/vt102 OLD_FILES+=usr/share/terminfo/v/vt102+enq OLD_FILES+=usr/share/terminfo/v/vt102-nsgr OLD_FILES+=usr/share/terminfo/v/vt102-w OLD_FILES+=usr/share/terminfo/v/vt125 OLD_FILES+=usr/share/terminfo/v/vt131 OLD_FILES+=usr/share/terminfo/v/vt132 OLD_FILES+=usr/share/terminfo/v/vt200 OLD_FILES+=usr/share/terminfo/v/vt200-8 OLD_FILES+=usr/share/terminfo/v/vt200-8bit OLD_FILES+=usr/share/terminfo/v/vt200-js OLD_FILES+=usr/share/terminfo/v/vt200-old OLD_FILES+=usr/share/terminfo/v/vt200-w OLD_FILES+=usr/share/terminfo/v/vt220 OLD_FILES+=usr/share/terminfo/v/vt220+cvis OLD_FILES+=usr/share/terminfo/v/vt220+cvis8 OLD_FILES+=usr/share/terminfo/v/vt220+keypad OLD_FILES+=usr/share/terminfo/v/vt220+pcedit OLD_FILES+=usr/share/terminfo/v/vt220+vtedit OLD_FILES+=usr/share/terminfo/v/vt220-8 OLD_FILES+=usr/share/terminfo/v/vt220-8bit OLD_FILES+=usr/share/terminfo/v/vt220-base OLD_FILES+=usr/share/terminfo/v/vt220-js OLD_FILES+=usr/share/terminfo/v/vt220-nam OLD_FILES+=usr/share/terminfo/v/vt220-old OLD_FILES+=usr/share/terminfo/v/vt220-w OLD_FILES+=usr/share/terminfo/v/vt220d OLD_FILES+=usr/share/terminfo/v/vt300 OLD_FILES+=usr/share/terminfo/v/vt300-nam OLD_FILES+=usr/share/terminfo/v/vt300-w OLD_FILES+=usr/share/terminfo/v/vt300-w-nam OLD_FILES+=usr/share/terminfo/v/vt320 OLD_FILES+=usr/share/terminfo/v/vt320-k3 OLD_FILES+=usr/share/terminfo/v/vt320-k311 OLD_FILES+=usr/share/terminfo/v/vt320-nam OLD_FILES+=usr/share/terminfo/v/vt320-w OLD_FILES+=usr/share/terminfo/v/vt320-w-nam OLD_FILES+=usr/share/terminfo/v/vt320nam OLD_FILES+=usr/share/terminfo/v/vt330 OLD_FILES+=usr/share/terminfo/v/vt340 OLD_FILES+=usr/share/terminfo/v/vt400 OLD_FILES+=usr/share/terminfo/v/vt400-24 OLD_FILES+=usr/share/terminfo/v/vt420 OLD_FILES+=usr/share/terminfo/v/vt420+lrmm OLD_FILES+=usr/share/terminfo/v/vt420f OLD_FILES+=usr/share/terminfo/v/vt420pc OLD_FILES+=usr/share/terminfo/v/vt420pcdos OLD_FILES+=usr/share/terminfo/v/vt50 OLD_FILES+=usr/share/terminfo/v/vt50h OLD_FILES+=usr/share/terminfo/v/vt510 OLD_FILES+=usr/share/terminfo/v/vt510pc OLD_FILES+=usr/share/terminfo/v/vt510pcdos OLD_FILES+=usr/share/terminfo/v/vt52 OLD_FILES+=usr/share/terminfo/v/vt52+keypad OLD_FILES+=usr/share/terminfo/v/vt52-basic OLD_FILES+=usr/share/terminfo/v/vt520 OLD_FILES+=usr/share/terminfo/v/vt520ansi OLD_FILES+=usr/share/terminfo/v/vt525 OLD_FILES+=usr/share/terminfo/v/vt61 OLD_FILES+=usr/share/terminfo/v/vt61.5 OLD_FILES+=usr/share/terminfo/v/vte OLD_FILES+=usr/share/terminfo/v/vte+pcfkeys OLD_FILES+=usr/share/terminfo/v/vte-2007 OLD_FILES+=usr/share/terminfo/v/vte-2008 OLD_FILES+=usr/share/terminfo/v/vte-2012 OLD_FILES+=usr/share/terminfo/v/vte-2014 OLD_FILES+=usr/share/terminfo/v/vte-2017 OLD_FILES+=usr/share/terminfo/v/vte-2018 OLD_FILES+=usr/share/terminfo/v/vte-256color OLD_FILES+=usr/share/terminfo/v/vte-direct OLD_FILES+=usr/share/terminfo/v/vtnt OLD_FILES+=usr/share/terminfo/v/vv100 OLD_FILES+=usr/share/terminfo/v/vwmterm OLD_DIRS+=usr/share/terminfo/v/ OLD_FILES+=usr/share/terminfo/w/wren OLD_FILES+=usr/share/terminfo/w/wrenw OLD_FILES+=usr/share/terminfo/w/wsiris OLD_FILES+=usr/share/terminfo/w/wsvt25 OLD_FILES+=usr/share/terminfo/w/wsvt25m OLD_FILES+=usr/share/terminfo/w/wy-75ap OLD_FILES+=usr/share/terminfo/w/wy-99fgt OLD_FILES+=usr/share/terminfo/w/wy-99fgta OLD_FILES+=usr/share/terminfo/w/wy100 OLD_FILES+=usr/share/terminfo/w/wy100q OLD_FILES+=usr/share/terminfo/w/wy120 OLD_FILES+=usr/share/terminfo/w/wy120-25 OLD_FILES+=usr/share/terminfo/w/wy120-25-w OLD_FILES+=usr/share/terminfo/w/wy120-vb OLD_FILES+=usr/share/terminfo/w/wy120-w OLD_FILES+=usr/share/terminfo/w/wy120-w-vb OLD_FILES+=usr/share/terminfo/w/wy120-wvb OLD_FILES+=usr/share/terminfo/w/wy150 OLD_FILES+=usr/share/terminfo/w/wy150-25 OLD_FILES+=usr/share/terminfo/w/wy150-25-w OLD_FILES+=usr/share/terminfo/w/wy150-vb OLD_FILES+=usr/share/terminfo/w/wy150-w OLD_FILES+=usr/share/terminfo/w/wy150-w-vb OLD_FILES+=usr/share/terminfo/w/wy160 OLD_FILES+=usr/share/terminfo/w/wy160-25 OLD_FILES+=usr/share/terminfo/w/wy160-25-w OLD_FILES+=usr/share/terminfo/w/wy160-42 OLD_FILES+=usr/share/terminfo/w/wy160-42-w OLD_FILES+=usr/share/terminfo/w/wy160-43 OLD_FILES+=usr/share/terminfo/w/wy160-43-w OLD_FILES+=usr/share/terminfo/w/wy160-tek OLD_FILES+=usr/share/terminfo/w/wy160-vb OLD_FILES+=usr/share/terminfo/w/wy160-w OLD_FILES+=usr/share/terminfo/w/wy160-w-vb OLD_FILES+=usr/share/terminfo/w/wy160-wvb OLD_FILES+=usr/share/terminfo/w/wy185 OLD_FILES+=usr/share/terminfo/w/wy185-24 OLD_FILES+=usr/share/terminfo/w/wy185-vb OLD_FILES+=usr/share/terminfo/w/wy185-w OLD_FILES+=usr/share/terminfo/w/wy185-wvb OLD_FILES+=usr/share/terminfo/w/wy30 OLD_FILES+=usr/share/terminfo/w/wy30-mc OLD_FILES+=usr/share/terminfo/w/wy30-vb OLD_FILES+=usr/share/terminfo/w/wy325 OLD_FILES+=usr/share/terminfo/w/wy325-25 OLD_FILES+=usr/share/terminfo/w/wy325-25w OLD_FILES+=usr/share/terminfo/w/wy325-42 OLD_FILES+=usr/share/terminfo/w/wy325-42w OLD_FILES+=usr/share/terminfo/w/wy325-42w-vb OLD_FILES+=usr/share/terminfo/w/wy325-42wvb OLD_FILES+=usr/share/terminfo/w/wy325-43 OLD_FILES+=usr/share/terminfo/w/wy325-43w OLD_FILES+=usr/share/terminfo/w/wy325-43w-vb OLD_FILES+=usr/share/terminfo/w/wy325-43wvb OLD_FILES+=usr/share/terminfo/w/wy325-80 OLD_FILES+=usr/share/terminfo/w/wy325-vb OLD_FILES+=usr/share/terminfo/w/wy325-w OLD_FILES+=usr/share/terminfo/w/wy325-w-vb OLD_FILES+=usr/share/terminfo/w/wy325-wvb OLD_FILES+=usr/share/terminfo/w/wy325w-24 OLD_FILES+=usr/share/terminfo/w/wy350 OLD_FILES+=usr/share/terminfo/w/wy350-vb OLD_FILES+=usr/share/terminfo/w/wy350-w OLD_FILES+=usr/share/terminfo/w/wy350-wvb OLD_FILES+=usr/share/terminfo/w/wy370 OLD_FILES+=usr/share/terminfo/w/wy370-101k OLD_FILES+=usr/share/terminfo/w/wy370-105k OLD_FILES+=usr/share/terminfo/w/wy370-EPC OLD_FILES+=usr/share/terminfo/w/wy370-nk OLD_FILES+=usr/share/terminfo/w/wy370-rv OLD_FILES+=usr/share/terminfo/w/wy370-tek OLD_FILES+=usr/share/terminfo/w/wy370-vb OLD_FILES+=usr/share/terminfo/w/wy370-w OLD_FILES+=usr/share/terminfo/w/wy370-wvb OLD_FILES+=usr/share/terminfo/w/wy50 OLD_FILES+=usr/share/terminfo/w/wy50-mc OLD_FILES+=usr/share/terminfo/w/wy50-vb OLD_FILES+=usr/share/terminfo/w/wy50-w OLD_FILES+=usr/share/terminfo/w/wy50-wvb OLD_FILES+=usr/share/terminfo/w/wy520 OLD_FILES+=usr/share/terminfo/w/wy520-24 OLD_FILES+=usr/share/terminfo/w/wy520-36 OLD_FILES+=usr/share/terminfo/w/wy520-36pc OLD_FILES+=usr/share/terminfo/w/wy520-36w OLD_FILES+=usr/share/terminfo/w/wy520-36wpc OLD_FILES+=usr/share/terminfo/w/wy520-48 OLD_FILES+=usr/share/terminfo/w/wy520-48pc OLD_FILES+=usr/share/terminfo/w/wy520-48w OLD_FILES+=usr/share/terminfo/w/wy520-48wpc OLD_FILES+=usr/share/terminfo/w/wy520-epc OLD_FILES+=usr/share/terminfo/w/wy520-epc-24 OLD_FILES+=usr/share/terminfo/w/wy520-epc-vb OLD_FILES+=usr/share/terminfo/w/wy520-epc-w OLD_FILES+=usr/share/terminfo/w/wy520-epc-wvb OLD_FILES+=usr/share/terminfo/w/wy520-vb OLD_FILES+=usr/share/terminfo/w/wy520-w OLD_FILES+=usr/share/terminfo/w/wy520-wvb OLD_FILES+=usr/share/terminfo/w/wy60 OLD_FILES+=usr/share/terminfo/w/wy60-25 OLD_FILES+=usr/share/terminfo/w/wy60-25-w OLD_FILES+=usr/share/terminfo/w/wy60-316X OLD_FILES+=usr/share/terminfo/w/wy60-42 OLD_FILES+=usr/share/terminfo/w/wy60-42-w OLD_FILES+=usr/share/terminfo/w/wy60-43 OLD_FILES+=usr/share/terminfo/w/wy60-43-w OLD_FILES+=usr/share/terminfo/w/wy60-AT OLD_FILES+=usr/share/terminfo/w/wy60-PC OLD_FILES+=usr/share/terminfo/w/wy60-vb OLD_FILES+=usr/share/terminfo/w/wy60-w OLD_FILES+=usr/share/terminfo/w/wy60-w-vb OLD_FILES+=usr/share/terminfo/w/wy60-wvb OLD_FILES+=usr/share/terminfo/w/wy75 OLD_FILES+=usr/share/terminfo/w/wy75-mc OLD_FILES+=usr/share/terminfo/w/wy75-vb OLD_FILES+=usr/share/terminfo/w/wy75-w OLD_FILES+=usr/share/terminfo/w/wy75-wvb OLD_FILES+=usr/share/terminfo/w/wy75ap OLD_FILES+=usr/share/terminfo/w/wy85 OLD_FILES+=usr/share/terminfo/w/wy85-8bit OLD_FILES+=usr/share/terminfo/w/wy85-vb OLD_FILES+=usr/share/terminfo/w/wy85-w OLD_FILES+=usr/share/terminfo/w/wy85-wvb OLD_FILES+=usr/share/terminfo/w/wy99-ansi OLD_FILES+=usr/share/terminfo/w/wy99a-ansi OLD_FILES+=usr/share/terminfo/w/wy99f OLD_FILES+=usr/share/terminfo/w/wy99fa OLD_FILES+=usr/share/terminfo/w/wy99fgt OLD_FILES+=usr/share/terminfo/w/wy99fgta OLD_FILES+=usr/share/terminfo/w/wy99gt OLD_FILES+=usr/share/terminfo/w/wy99gt-25 OLD_FILES+=usr/share/terminfo/w/wy99gt-25-w OLD_FILES+=usr/share/terminfo/w/wy99gt-tek OLD_FILES+=usr/share/terminfo/w/wy99gt-vb OLD_FILES+=usr/share/terminfo/w/wy99gt-w OLD_FILES+=usr/share/terminfo/w/wy99gt-w-vb OLD_FILES+=usr/share/terminfo/w/wy99gt-wvb OLD_FILES+=usr/share/terminfo/w/wyse-325 OLD_FILES+=usr/share/terminfo/w/wyse-75ap OLD_FILES+=usr/share/terminfo/w/wyse-vp OLD_FILES+=usr/share/terminfo/w/wyse120 OLD_FILES+=usr/share/terminfo/w/wyse120-25 OLD_FILES+=usr/share/terminfo/w/wyse120-25-w OLD_FILES+=usr/share/terminfo/w/wyse120-vb OLD_FILES+=usr/share/terminfo/w/wyse120-w OLD_FILES+=usr/share/terminfo/w/wyse120-wvb OLD_FILES+=usr/share/terminfo/w/wyse150 OLD_FILES+=usr/share/terminfo/w/wyse150-25 OLD_FILES+=usr/share/terminfo/w/wyse150-25-w OLD_FILES+=usr/share/terminfo/w/wyse150-vb OLD_FILES+=usr/share/terminfo/w/wyse150-w OLD_FILES+=usr/share/terminfo/w/wyse150-w-vb OLD_FILES+=usr/share/terminfo/w/wyse160 OLD_FILES+=usr/share/terminfo/w/wyse160-25 OLD_FILES+=usr/share/terminfo/w/wyse160-25-w OLD_FILES+=usr/share/terminfo/w/wyse160-42 OLD_FILES+=usr/share/terminfo/w/wyse160-42-w OLD_FILES+=usr/share/terminfo/w/wyse160-43 OLD_FILES+=usr/share/terminfo/w/wyse160-43-w OLD_FILES+=usr/share/terminfo/w/wyse160-vb OLD_FILES+=usr/share/terminfo/w/wyse160-w OLD_FILES+=usr/share/terminfo/w/wyse160-wvb OLD_FILES+=usr/share/terminfo/w/wyse185 OLD_FILES+=usr/share/terminfo/w/wyse185-24 OLD_FILES+=usr/share/terminfo/w/wyse185-vb OLD_FILES+=usr/share/terminfo/w/wyse185-w OLD_FILES+=usr/share/terminfo/w/wyse185-wvb OLD_FILES+=usr/share/terminfo/w/wyse30 OLD_FILES+=usr/share/terminfo/w/wyse30-mc OLD_FILES+=usr/share/terminfo/w/wyse30-vb OLD_FILES+=usr/share/terminfo/w/wyse325 OLD_FILES+=usr/share/terminfo/w/wyse325-25 OLD_FILES+=usr/share/terminfo/w/wyse325-25w OLD_FILES+=usr/share/terminfo/w/wyse325-42 OLD_FILES+=usr/share/terminfo/w/wyse325-42w OLD_FILES+=usr/share/terminfo/w/wyse325-43 OLD_FILES+=usr/share/terminfo/w/wyse325-43w OLD_FILES+=usr/share/terminfo/w/wyse325-vb OLD_FILES+=usr/share/terminfo/w/wyse325-w OLD_FILES+=usr/share/terminfo/w/wyse325-wvb OLD_FILES+=usr/share/terminfo/w/wyse350 OLD_FILES+=usr/share/terminfo/w/wyse350-vb OLD_FILES+=usr/share/terminfo/w/wyse350-w OLD_FILES+=usr/share/terminfo/w/wyse350-wvb OLD_FILES+=usr/share/terminfo/w/wyse370 OLD_FILES+=usr/share/terminfo/w/wyse50 OLD_FILES+=usr/share/terminfo/w/wyse50-mc OLD_FILES+=usr/share/terminfo/w/wyse50-vb OLD_FILES+=usr/share/terminfo/w/wyse50-w OLD_FILES+=usr/share/terminfo/w/wyse50-wvb OLD_FILES+=usr/share/terminfo/w/wyse520 OLD_FILES+=usr/share/terminfo/w/wyse520-24 OLD_FILES+=usr/share/terminfo/w/wyse520-36 OLD_FILES+=usr/share/terminfo/w/wyse520-36pc OLD_FILES+=usr/share/terminfo/w/wyse520-36w OLD_FILES+=usr/share/terminfo/w/wyse520-36wpc OLD_FILES+=usr/share/terminfo/w/wyse520-48 OLD_FILES+=usr/share/terminfo/w/wyse520-48pc OLD_FILES+=usr/share/terminfo/w/wyse520-48w OLD_FILES+=usr/share/terminfo/w/wyse520-48wpc OLD_FILES+=usr/share/terminfo/w/wyse520-epc OLD_FILES+=usr/share/terminfo/w/wyse520-epc-w OLD_FILES+=usr/share/terminfo/w/wyse520-p-wvb OLD_FILES+=usr/share/terminfo/w/wyse520-pc-24 OLD_FILES+=usr/share/terminfo/w/wyse520-pc-vb OLD_FILES+=usr/share/terminfo/w/wyse520-vb OLD_FILES+=usr/share/terminfo/w/wyse520-w OLD_FILES+=usr/share/terminfo/w/wyse520-wvb OLD_FILES+=usr/share/terminfo/w/wyse60 OLD_FILES+=usr/share/terminfo/w/wyse60-25 OLD_FILES+=usr/share/terminfo/w/wyse60-25-w OLD_FILES+=usr/share/terminfo/w/wyse60-316X OLD_FILES+=usr/share/terminfo/w/wyse60-42 OLD_FILES+=usr/share/terminfo/w/wyse60-42-w OLD_FILES+=usr/share/terminfo/w/wyse60-43 OLD_FILES+=usr/share/terminfo/w/wyse60-43-w OLD_FILES+=usr/share/terminfo/w/wyse60-AT OLD_FILES+=usr/share/terminfo/w/wyse60-PC OLD_FILES+=usr/share/terminfo/w/wyse60-vb OLD_FILES+=usr/share/terminfo/w/wyse60-w OLD_FILES+=usr/share/terminfo/w/wyse60-wvb OLD_FILES+=usr/share/terminfo/w/wyse75 OLD_FILES+=usr/share/terminfo/w/wyse75-mc OLD_FILES+=usr/share/terminfo/w/wyse75-vb OLD_FILES+=usr/share/terminfo/w/wyse75-w OLD_FILES+=usr/share/terminfo/w/wyse75-wvb OLD_FILES+=usr/share/terminfo/w/wyse75ap OLD_FILES+=usr/share/terminfo/w/wyse85 OLD_FILES+=usr/share/terminfo/w/wyse85-8bit OLD_FILES+=usr/share/terminfo/w/wyse85-vb OLD_FILES+=usr/share/terminfo/w/wyse85-w OLD_FILES+=usr/share/terminfo/w/wyse85-wvb OLD_FILES+=usr/share/terminfo/w/wyse99gt OLD_FILES+=usr/share/terminfo/w/wyse99gt-25 OLD_FILES+=usr/share/terminfo/w/wyse99gt-25-w OLD_FILES+=usr/share/terminfo/w/wyse99gt-vb OLD_FILES+=usr/share/terminfo/w/wyse99gt-w OLD_FILES+=usr/share/terminfo/w/wyse99gt-wvb OLD_DIRS+=usr/share/terminfo/w/ OLD_FILES+=usr/share/terminfo/x/x10term OLD_FILES+=usr/share/terminfo/x/x1700 OLD_FILES+=usr/share/terminfo/x/x1700-lm OLD_FILES+=usr/share/terminfo/x/x1720 OLD_FILES+=usr/share/terminfo/x/x1750 OLD_FILES+=usr/share/terminfo/x/x68k OLD_FILES+=usr/share/terminfo/x/x68k-ite OLD_FILES+=usr/share/terminfo/x/x820 OLD_FILES+=usr/share/terminfo/x/xdku OLD_FILES+=usr/share/terminfo/x/xenix OLD_FILES+=usr/share/terminfo/x/xerox OLD_FILES+=usr/share/terminfo/x/xerox-lm OLD_FILES+=usr/share/terminfo/x/xerox1720 OLD_FILES+=usr/share/terminfo/x/xerox820 OLD_FILES+=usr/share/terminfo/x/xfce OLD_FILES+=usr/share/terminfo/x/xiterm OLD_FILES+=usr/share/terminfo/x/xl83 OLD_FILES+=usr/share/terminfo/x/xnuppc OLD_FILES+=usr/share/terminfo/x/xnuppc+100x37 OLD_FILES+=usr/share/terminfo/x/xnuppc+112x37 OLD_FILES+=usr/share/terminfo/x/xnuppc+128x40 OLD_FILES+=usr/share/terminfo/x/xnuppc+128x48 OLD_FILES+=usr/share/terminfo/x/xnuppc+144x48 OLD_FILES+=usr/share/terminfo/x/xnuppc+160x64 OLD_FILES+=usr/share/terminfo/x/xnuppc+200x64 OLD_FILES+=usr/share/terminfo/x/xnuppc+200x75 OLD_FILES+=usr/share/terminfo/x/xnuppc+256x96 OLD_FILES+=usr/share/terminfo/x/xnuppc+80x25 OLD_FILES+=usr/share/terminfo/x/xnuppc+80x30 OLD_FILES+=usr/share/terminfo/x/xnuppc+90x30 OLD_FILES+=usr/share/terminfo/x/xnuppc+b OLD_FILES+=usr/share/terminfo/x/xnuppc+basic OLD_FILES+=usr/share/terminfo/x/xnuppc+c OLD_FILES+=usr/share/terminfo/x/xnuppc+f OLD_FILES+=usr/share/terminfo/x/xnuppc+f2 OLD_FILES+=usr/share/terminfo/x/xnuppc-100x37 OLD_FILES+=usr/share/terminfo/x/xnuppc-100x37-m OLD_FILES+=usr/share/terminfo/x/xnuppc-112x37 OLD_FILES+=usr/share/terminfo/x/xnuppc-112x37-m OLD_FILES+=usr/share/terminfo/x/xnuppc-128x40 OLD_FILES+=usr/share/terminfo/x/xnuppc-128x40-m OLD_FILES+=usr/share/terminfo/x/xnuppc-128x48 OLD_FILES+=usr/share/terminfo/x/xnuppc-128x48-m OLD_FILES+=usr/share/terminfo/x/xnuppc-144x48 OLD_FILES+=usr/share/terminfo/x/xnuppc-144x48-m OLD_FILES+=usr/share/terminfo/x/xnuppc-160x64 OLD_FILES+=usr/share/terminfo/x/xnuppc-160x64-m OLD_FILES+=usr/share/terminfo/x/xnuppc-200x64 OLD_FILES+=usr/share/terminfo/x/xnuppc-200x64-m OLD_FILES+=usr/share/terminfo/x/xnuppc-200x75 OLD_FILES+=usr/share/terminfo/x/xnuppc-200x75-m OLD_FILES+=usr/share/terminfo/x/xnuppc-256x96 OLD_FILES+=usr/share/terminfo/x/xnuppc-256x96-m OLD_FILES+=usr/share/terminfo/x/xnuppc-80x25 OLD_FILES+=usr/share/terminfo/x/xnuppc-80x25-m OLD_FILES+=usr/share/terminfo/x/xnuppc-80x30 OLD_FILES+=usr/share/terminfo/x/xnuppc-80x30-m OLD_FILES+=usr/share/terminfo/x/xnuppc-90x30 OLD_FILES+=usr/share/terminfo/x/xnuppc-90x30-m OLD_FILES+=usr/share/terminfo/x/xnuppc-b OLD_FILES+=usr/share/terminfo/x/xnuppc-f OLD_FILES+=usr/share/terminfo/x/xnuppc-f2 OLD_FILES+=usr/share/terminfo/x/xnuppc-m OLD_FILES+=usr/share/terminfo/x/xnuppc-m-b OLD_FILES+=usr/share/terminfo/x/xnuppc-m-f OLD_FILES+=usr/share/terminfo/x/xnuppc-m-f2 OLD_FILES+=usr/share/terminfo/x/xtalk OLD_FILES+=usr/share/terminfo/x/xterm OLD_FILES+=usr/share/terminfo/x/xterm+256color OLD_FILES+=usr/share/terminfo/x/xterm+256color2 OLD_FILES+=usr/share/terminfo/x/xterm+256setaf OLD_FILES+=usr/share/terminfo/x/xterm+88color OLD_FILES+=usr/share/terminfo/x/xterm+88color2 OLD_FILES+=usr/share/terminfo/x/xterm+alt+title OLD_FILES+=usr/share/terminfo/x/xterm+alt1049 OLD_FILES+=usr/share/terminfo/x/xterm+app OLD_FILES+=usr/share/terminfo/x/xterm+direct OLD_FILES+=usr/share/terminfo/x/xterm+direct16 OLD_FILES+=usr/share/terminfo/x/xterm+direct2 OLD_FILES+=usr/share/terminfo/x/xterm+direct256 OLD_FILES+=usr/share/terminfo/x/xterm+edit OLD_FILES+=usr/share/terminfo/x/xterm+indirect OLD_FILES+=usr/share/terminfo/x/xterm+kbs OLD_FILES+=usr/share/terminfo/x/xterm+keypad OLD_FILES+=usr/share/terminfo/x/xterm+meta OLD_FILES+=usr/share/terminfo/x/xterm+noalt OLD_FILES+=usr/share/terminfo/x/xterm+noapp OLD_FILES+=usr/share/terminfo/x/xterm+nofkeys OLD_FILES+=usr/share/terminfo/x/xterm+osc104 OLD_FILES+=usr/share/terminfo/x/xterm+pc+edit OLD_FILES+=usr/share/terminfo/x/xterm+pcc0 OLD_FILES+=usr/share/terminfo/x/xterm+pcc1 OLD_FILES+=usr/share/terminfo/x/xterm+pcc2 OLD_FILES+=usr/share/terminfo/x/xterm+pcc3 OLD_FILES+=usr/share/terminfo/x/xterm+pce2 OLD_FILES+=usr/share/terminfo/x/xterm+pcf0 OLD_FILES+=usr/share/terminfo/x/xterm+pcf2 OLD_FILES+=usr/share/terminfo/x/xterm+pcfkeys OLD_FILES+=usr/share/terminfo/x/xterm+r6f2 OLD_FILES+=usr/share/terminfo/x/xterm+sl OLD_FILES+=usr/share/terminfo/x/xterm+sl-twm OLD_FILES+=usr/share/terminfo/x/xterm+sm+1002 OLD_FILES+=usr/share/terminfo/x/xterm+sm+1003 OLD_FILES+=usr/share/terminfo/x/xterm+sm+1005 OLD_FILES+=usr/share/terminfo/x/xterm+sm+1006 OLD_FILES+=usr/share/terminfo/x/xterm+titlestack OLD_FILES+=usr/share/terminfo/x/xterm+tmux OLD_FILES+=usr/share/terminfo/x/xterm+vt+edit OLD_FILES+=usr/share/terminfo/x/xterm+x10mouse OLD_FILES+=usr/share/terminfo/x/xterm+x11hilite OLD_FILES+=usr/share/terminfo/x/xterm+x11mouse OLD_FILES+=usr/share/terminfo/x/xterm-1002 OLD_FILES+=usr/share/terminfo/x/xterm-1003 OLD_FILES+=usr/share/terminfo/x/xterm-1005 OLD_FILES+=usr/share/terminfo/x/xterm-1006 OLD_FILES+=usr/share/terminfo/x/xterm-16color OLD_FILES+=usr/share/terminfo/x/xterm-24 OLD_FILES+=usr/share/terminfo/x/xterm-256color OLD_FILES+=usr/share/terminfo/x/xterm-88color OLD_FILES+=usr/share/terminfo/x/xterm-8bit OLD_FILES+=usr/share/terminfo/x/xterm-basic OLD_FILES+=usr/share/terminfo/x/xterm-bold OLD_FILES+=usr/share/terminfo/x/xterm-color OLD_FILES+=usr/share/terminfo/x/xterm-direct OLD_FILES+=usr/share/terminfo/x/xterm-direct16 OLD_FILES+=usr/share/terminfo/x/xterm-direct2 OLD_FILES+=usr/share/terminfo/x/xterm-direct256 OLD_FILES+=usr/share/terminfo/x/xterm-hp OLD_FILES+=usr/share/terminfo/x/xterm-mono OLD_FILES+=usr/share/terminfo/x/xterm-new OLD_FILES+=usr/share/terminfo/x/xterm-nic OLD_FILES+=usr/share/terminfo/x/xterm-noapp OLD_FILES+=usr/share/terminfo/x/xterm-old OLD_FILES+=usr/share/terminfo/x/xterm-pcolor OLD_FILES+=usr/share/terminfo/x/xterm-r5 OLD_FILES+=usr/share/terminfo/x/xterm-r6 OLD_FILES+=usr/share/terminfo/x/xterm-sco OLD_FILES+=usr/share/terminfo/x/xterm-sun OLD_FILES+=usr/share/terminfo/x/xterm-utf8 OLD_FILES+=usr/share/terminfo/x/xterm-vt220 OLD_FILES+=usr/share/terminfo/x/xterm-vt52 OLD_FILES+=usr/share/terminfo/x/xterm-x10mouse OLD_FILES+=usr/share/terminfo/x/xterm-x11hilite OLD_FILES+=usr/share/terminfo/x/xterm-x11mouse OLD_FILES+=usr/share/terminfo/x/xterm-xf86-v32 OLD_FILES+=usr/share/terminfo/x/xterm-xf86-v33 OLD_FILES+=usr/share/terminfo/x/xterm-xf86-v333 OLD_FILES+=usr/share/terminfo/x/xterm-xf86-v40 OLD_FILES+=usr/share/terminfo/x/xterm-xf86-v43 OLD_FILES+=usr/share/terminfo/x/xterm-xf86-v44 OLD_FILES+=usr/share/terminfo/x/xterm-xfree86 OLD_FILES+=usr/share/terminfo/x/xterm-xi OLD_FILES+=usr/share/terminfo/x/xterm.js OLD_FILES+=usr/share/terminfo/x/xterm1 OLD_FILES+=usr/share/terminfo/x/xtermc OLD_FILES+=usr/share/terminfo/x/xtermm OLD_FILES+=usr/share/terminfo/x/xterms OLD_FILES+=usr/share/terminfo/x/xterms-sun OLD_FILES+=usr/share/terminfo/x/xwsh OLD_DIRS+=usr/share/terminfo/x/ OLD_FILES+=usr/share/terminfo/z/z-100 OLD_FILES+=usr/share/terminfo/z/z-100bw OLD_FILES+=usr/share/terminfo/z/z100 OLD_FILES+=usr/share/terminfo/z/z100bw OLD_FILES+=usr/share/terminfo/z/z110 OLD_FILES+=usr/share/terminfo/z/z110bw OLD_FILES+=usr/share/terminfo/z/z19 OLD_FILES+=usr/share/terminfo/z/z29 OLD_FILES+=usr/share/terminfo/z/z29a OLD_FILES+=usr/share/terminfo/z/z29a-kc-bc OLD_FILES+=usr/share/terminfo/z/z29a-kc-uc OLD_FILES+=usr/share/terminfo/z/z29a-nkc-bc OLD_FILES+=usr/share/terminfo/z/z29a-nkc-uc OLD_FILES+=usr/share/terminfo/z/z29b OLD_FILES+=usr/share/terminfo/z/z30 OLD_FILES+=usr/share/terminfo/z/z340 OLD_FILES+=usr/share/terminfo/z/z340-nam OLD_FILES+=usr/share/terminfo/z/z39-a OLD_FILES+=usr/share/terminfo/z/z39a OLD_FILES+=usr/share/terminfo/z/z50 OLD_FILES+=usr/share/terminfo/z/z8001 OLD_FILES+=usr/share/terminfo/z/zen30 OLD_FILES+=usr/share/terminfo/z/zen50 OLD_FILES+=usr/share/terminfo/z/zen8001 OLD_FILES+=usr/share/terminfo/z/zenith OLD_FILES+=usr/share/terminfo/z/zenith29 OLD_FILES+=usr/share/terminfo/z/zenith39-a OLD_FILES+=usr/share/terminfo/z/zenith39-ansi OLD_FILES+=usr/share/terminfo/z/zt-1 OLD_FILES+=usr/share/terminfo/z/ztx OLD_FILES+=usr/share/terminfo/z/ztx-1-a OLD_FILES+=usr/share/terminfo/z/ztx11 OLD_DIRS+=usr/share/terminfo/z/ OLD_DIRS+=usr/share/terminfo/ # 20210316: remove obsolete NFS headers OLD_FILES+=usr/include/nfs/nfs_common.h OLD_FILES+=usr/include/nfsclient/nfsm_subs.h OLD_FILES+=usr/include/nfsclient/nlminfo.h OLD_FILES+=usr/include/nfsserver/nfs_fha_old.h OLD_FILES+=usr/include/nfsserver/nfsm_subs.h OLD_FILES+=usr/include/nfsserver/nfsrvcache.h # 20210315: Remove kernel-only crypto headers from /usr/include OLD_FILES+=usr/include/crypto/_cryptodev.h OLD_FILES+=usr/include/crypto/cbc_mac.h OLD_FILES+=usr/include/crypto/deflate.h OLD_FILES+=usr/include/crypto/gfmult.h OLD_FILES+=usr/include/crypto/gmac.h OLD_FILES+=usr/include/crypto/rijndael.h OLD_FILES+=usr/include/crypto/rmd160.h OLD_FILES+=usr/include/crypto/xform.h OLD_FILES+=usr/include/crypto/xform_auth.h OLD_FILES+=usr/include/crypto/xform_comp.h OLD_FILES+=usr/include/crypto/xform_enc.h # 20210305: removed Poly1305_* symbols OLD_FILES+=usr/include/crypto/xform_poly1305.h # 20210302: fmtree removed OLD_FILES+=usr/sbin/fmtree OLD_FILES+=usr/share/man/man8/fmtree.8.gz # 20210201: bump shared libraries which link against ncurses OLD_LIBS+=lib/libedit.so.7 OLD_LIBS+=usr/lib/libdialog.so.8 OLD_LIBS+=usr/lib/libdpv.so.1 OLD_LIBS+=usr/lib/libform.so.5 OLD_LIBS+=usr/lib/libformw.so.5 OLD_LIBS+=usr/lib/libmenu.so.5 OLD_LIBS+=usr/lib/libmenuw.so.5 OLD_LIBS+=usr/lib/libpanel.so.5 OLD_LIBS+=usr/lib/libpanelw.so.5 # 20210125: ndis driver support removed OLD_FILES+=usr/sbin/ndis_events OLD_FILES+=usr/sbin/ndiscvt OLD_FILES+=usr/sbin/ndisgen OLD_FILES+=usr/share/man/man4/ndis.4.gz OLD_FILES+=usr/share/man/man4/if_ndis.4.gz OLD_FILES+=usr/share/man/man8/ndis_events.8.gz OLD_FILES+=usr/share/man/man8/ndiscvt.8.gz OLD_FILES+=usr/share/man/man8/ndisgen.8.gz OLD_FILES+=usr/share/misc/windrv_stub.c # 20210116: openpromio(4) removed OLD_FILES+=usr/include/dev/ofw/openpromio.h # 20210116: if_wl_wavelan.h removed .if ${TARGET_ARCH} == "i386" OLD_FILES+=usr/include/machine/if_wl_wavelan.h .endif # 20210108: retire cmx, ng_bt3c, wi drivers OLD_FILES+=usr/include/dev/wi/if_wireg.h OLD_FILES+=usr/include/dev/wi/if_wavelan_ieee.h OLD_FILES+=usr/include/dev/wi/if_wivar.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_bt3c.h OLD_FILES+=usr/sbin/bt3cfw OLD_FILES+=usr/share/man/man4/cmw.4.gz OLD_FILES+=usr/share/man/man4/if_wi.4.gz OLD_FILES+=usr/share/man/man4/ng_bt3c.4.gz OLD_FILES+=usr/share/man/man4/wi.4.gz OLD_FILES+=usr/share/man/man8/bt3cfw.8.gz # 20210107: retire a.out support OLD_DIRS+=usr/lib/aout OLD_DIRS+=usr/lib/compat/aout # 20210107: remove cmx(4) OLD_FILES+=usr/share/man/man4/cmx.4.gz # 20210105: remove non widechar version of ncurses OLD_LIBS+=lib/libncurses.so.9 # 20210103: new clang import which bumps version from 11.0.0 to 11.0.1 OLD_FILES+=usr/lib/clang/11.0.0/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/11.0.0/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/11.0.0/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/11.0.0/include/cuda_wrappers OLD_FILES+=usr/lib/clang/11.0.0/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/11.0.0/include/fuzzer OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/__clang_openmp_device_functions.h OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/complex OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/complex.h OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/math.h OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/new OLD_DIRS+=usr/lib/clang/11.0.0/include/openmp_wrappers OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/11.0.0/include/ppc_wrappers OLD_FILES+=usr/lib/clang/11.0.0/include/profile/InstrProfData.inc OLD_DIRS+=usr/lib/clang/11.0.0/include/profile OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/11.0.0/include/sanitizer OLD_FILES+=usr/lib/clang/11.0.0/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/11.0.0/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/11.0.0/include/xray OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_math.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_hip_libdevice_declares.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_hip_math.h OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_hip_runtime_wrapper.h OLD_FILES+=usr/lib/clang/11.0.0/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/11.0.0/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/11.0.0/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/11.0.0/include/adxintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/altivec.h OLD_FILES+=usr/lib/clang/11.0.0/include/ammintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/amxintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/arm64intr.h OLD_FILES+=usr/lib/clang/11.0.0/include/arm_acle.h OLD_FILES+=usr/lib/clang/11.0.0/include/arm_bf16.h OLD_FILES+=usr/lib/clang/11.0.0/include/arm_cde.h OLD_FILES+=usr/lib/clang/11.0.0/include/arm_cmse.h OLD_FILES+=usr/lib/clang/11.0.0/include/arm_fp16.h OLD_FILES+=usr/lib/clang/11.0.0/include/arm_mve.h OLD_FILES+=usr/lib/clang/11.0.0/include/arm_neon.h OLD_FILES+=usr/lib/clang/11.0.0/include/arm_sve.h OLD_FILES+=usr/lib/clang/11.0.0/include/armintr.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx2intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/avxintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/bmiintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/cet.h OLD_FILES+=usr/lib/clang/11.0.0/include/cetintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/clwbintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/clzerointrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/cpuid.h OLD_FILES+=usr/lib/clang/11.0.0/include/emmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/f16cintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/fma4intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/fmaintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/gfniintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/htmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/ia32intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/immintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/lwpintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/mm3dnow.h OLD_FILES+=usr/lib/clang/11.0.0/include/mm_malloc.h OLD_FILES+=usr/lib/clang/11.0.0/include/mmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/module.modulemap OLD_FILES+=usr/lib/clang/11.0.0/include/movdirintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/msa.h OLD_FILES+=usr/lib/clang/11.0.0/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/nmmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/11.0.0/include/opencl-c.h OLD_FILES+=usr/lib/clang/11.0.0/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/pkuintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/pmmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/popcntintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/rtmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/s390intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/serializeintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/sgxintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/shaintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/smmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/tbmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/tmmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/tsxldtrkintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/vadefs.h OLD_FILES+=usr/lib/clang/11.0.0/include/vaesintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/vecintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/wasm_simd128.h OLD_FILES+=usr/lib/clang/11.0.0/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/wmmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/x86intrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/xmmintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/xopintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/11.0.0/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/11.0.0/include OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-powerpc64le.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/11.0.0/lib/freebsd OLD_DIRS+=usr/lib/clang/11.0.0/lib OLD_DIRS+=usr/lib/clang/11.0.0 # 20201226: Siemens SAB 82532 support removed OLD_FILES+=usr/include/dev/ic/sab82532.h # 20201225: PMC for Xscale removed OLD_FILES+=usr/include/dev/hwpmc/hwpmc_xscale.h OLD_FILES+=usr/share/man/man3/pmc.xscale.3.gz # 20201225: libregex removed OLD_FILES+=usr/include/gnu/posix/regex.h OLD_DIRS+=usr/include/gnu/posix OLD_FILES+=usr/include/gnu/regex.h OLD_DIRS+=usr/include/gnu OLD_FILES+=usr/include/gnuregex.h OLD_FILES+=usr/lib/libgnuregex.a OLD_FILES+=usr/lib/libgnuregex.so OLD_LIBS+=usr/lib/libgnuregex.so.5 OLD_FILES+=usr/lib/libgnuregex_p.a # 20201225: gnugrep removed OLD_FILES+=usr/bin/bsdgrep OLD_FILES+=usr/bin/gnugrep OLD_FILES+=usr/share/man/man1/bsdgrep.1.gz OLD_FILES+=usr/share/man/man1/gnugrep.1.gz # 20201224: mk48txx(4) removed OLD_FILES+=usr/share/man/man4/mk48txx.4.gz # 20201215: in-tree gdb removed OLD_FILES+=usr/libexec/gdb OLD_FILES+=usr/libexec/kgdb # 20201211: hme(4) removed OLD_FILES+=usr/share/man/man4/hme.4.gz OLD_FILES+=usr/share/man/man4/if_hme.4.gz # 20201129: RADIX_MPATH removed OLD_FILES+=usr/include/net/radix_mpath.h # 20201124: ping6(8) was merged into ping(8) OLD_FILES+=usr/tests/sbin/ping6/Kyuafile OLD_FILES+=usr/tests/sbin/ping6/ping6_c1_s8_t1.out OLD_FILES+=usr/tests/sbin/ping6/ping6_test OLD_DIRS+=usr/tests/sbin/ping6 # 20201025: Remove cal data files OLD_FILES+=usr/share/calendar/calendar.all OLD_FILES+=usr/share/calendar/calendar.australia OLD_FILES+=usr/share/calendar/calendar.birthday OLD_FILES+=usr/share/calendar/calendar.brazilian OLD_FILES+=usr/share/calendar/calendar.christian OLD_FILES+=usr/share/calendar/calendar.computer OLD_FILES+=usr/share/calendar/calendar.croatian OLD_FILES+=usr/share/calendar/calendar.dutch OLD_FILES+=usr/share/calendar/calendar.french OLD_FILES+=usr/share/calendar/calendar.german OLD_FILES+=usr/share/calendar/calendar.history OLD_FILES+=usr/share/calendar/calendar.holiday OLD_FILES+=usr/share/calendar/calendar.hungarian OLD_FILES+=usr/share/calendar/calendar.judaic OLD_FILES+=usr/share/calendar/calendar.lotr OLD_FILES+=usr/share/calendar/calendar.music OLD_FILES+=usr/share/calendar/calendar.newzealand OLD_FILES+=usr/share/calendar/calendar.russian OLD_FILES+=usr/share/calendar/calendar.southafrica OLD_FILES+=usr/share/calendar/calendar.ukrainian OLD_FILES+=usr/share/calendar/calendar.usholiday OLD_FILES+=usr/share/calendar/calendar.world OLD_FILES+=usr/share/calendar/de_AT.ISO_8859-15/calendar.feiertag OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.all OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.feiertag OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.geschichte OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.kirche OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.literatur OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.musik OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.wissenschaft OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.all OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.fetes OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.french OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.jferies OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.proverbes OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.all OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.praznici OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.all OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.nevnapok OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.unnepek OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.all OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.commemorative OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.holidays OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.mcommemorative OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.all OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.commemorative OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.holidays OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.mcommemorative OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.all OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.common OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.holiday OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.military OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.orthodox OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.pagan OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.all OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.common OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.holiday OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.military OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.orthodox OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.pagan OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.all OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.holiday OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.misc OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.orthodox OLD_DIRS+=usr/share/calendar/de_AT.ISO_8859-15 OLD_DIRS+=usr/share/calendar/de_DE.ISO8859-1 OLD_FILES+=usr/share/calendar/de_DE.ISO8859-15 OLD_DIRS+=usr/share/calendar/fr_FR.ISO8859-1 OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-15 OLD_DIRS+=usr/share/calendar/hr_HR.ISO8859-2 OLD_DIRS+=usr/share/calendar/hu_HU.ISO8859-2 OLD_DIRS+=usr/share/calendar/pt_BR.ISO8859-1 OLD_DIRS+=usr/share/calendar/pt_BR.UTF-8 OLD_DIRS+=usr/share/calendar/ru_RU.KOI8-R OLD_DIRS+=usr/share/calendar/ru_RU.UTF-8 OLD_DIRS+=usr/share/calendar/uk_UA.KOI8-U # 20201004: logo files renamed to type-agnostic gfx-*.lua OLD_FILES+=boot/lua/logo-beastie.lua OLD_FILES+=boot/lua/logo-beastiebw.lua OLD_FILES+=boot/lua/logo-fbsdbw.lua OLD_FILES+=boot/lua/logo-orb.lua OLD_FILES+=boot/lua/logo-orbbw.lua # 20200828: net/route/shared.h moved to net/route/route_var.h OLD_FILES+=usr/include/net/route/shared.h # 20200825: merged OpenZFS support OLD_LIBS+=lib/libzfs.so.3 OLD_FILES+=usr/share/man/man1/zstreamdump.1.gz #OLD_FILES+=usr/share/man/man7/zpool-features.7.gz # 20200923: memfd_test moved to /usr/tests/sys/posixshm OLD_FILES+=usr/tests/sys/kern/memfd_test # 20200910: remove vm_map_create(9) to sync with the code OLD_FILES+=usr/share/man/man9/vm_map_create.9.gz # 20200820: Removal of the ufm driver OLD_FILES+=usr/share/man/man4/ufm.4.gz # 20200816: new clang import which bumps version from 10.0.1 to 11.0.0 OLD_FILES+=usr/lib/clang/10.0.1/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/10.0.1/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/10.0.1/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/10.0.1/include/cuda_wrappers OLD_FILES+=usr/lib/clang/10.0.1/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/10.0.1/include/fuzzer OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/__clang_openmp_math.h OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/__clang_openmp_math_declares.h OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/math.h OLD_DIRS+=usr/lib/clang/10.0.1/include/openmp_wrappers OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/10.0.1/include/ppc_wrappers OLD_FILES+=usr/lib/clang/10.0.1/include/profile/InstrProfData.inc OLD_DIRS+=usr/lib/clang/10.0.1/include/profile OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/10.0.1/include/sanitizer OLD_FILES+=usr/lib/clang/10.0.1/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/10.0.1/include/xray OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/10.0.1/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/10.0.1/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/10.0.1/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/10.0.1/include/adxintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/altivec.h OLD_FILES+=usr/lib/clang/10.0.1/include/ammintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm64intr.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_acle.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_cmse.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_fp16.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_mve.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_neon.h OLD_FILES+=usr/lib/clang/10.0.1/include/armintr.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx2intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avxintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/bmiintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/cetintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/clwbintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/clzerointrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/cpuid.h OLD_FILES+=usr/lib/clang/10.0.1/include/emmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/f16cintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/fma4intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/fmaintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/gfniintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/htmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ia32intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/immintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/lwpintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/mm3dnow.h OLD_FILES+=usr/lib/clang/10.0.1/include/mm_malloc.h OLD_FILES+=usr/lib/clang/10.0.1/include/mmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/module.modulemap OLD_FILES+=usr/lib/clang/10.0.1/include/movdirintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/msa.h OLD_FILES+=usr/lib/clang/10.0.1/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/nmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/10.0.1/include/opencl-c.h OLD_FILES+=usr/lib/clang/10.0.1/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/pkuintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/pmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/popcntintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/rtmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/s390intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/sgxintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/shaintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/smmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/tbmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/tmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/vadefs.h OLD_FILES+=usr/lib/clang/10.0.1/include/vaesintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/vecintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/wmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/x86intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xopintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/10.0.1/include OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/10.0.1/lib/freebsd OLD_DIRS+=usr/lib/clang/10.0.1/lib OLD_DIRS+=usr/lib/clang/10.0.1 # 20200803: remove free_domain(9) and uma_zfree_domain(9) OLD_FILES+=usr/share/man/man9/free_domain.9.gz OLD_FILES+=usr/share/man/man9/uma_zfree_domain.9.gz # 20200729: remove long expired serial drivers OLD_FILES+=usr/share/man/man4/cy.4.gz OLD_FILES+=usr/share/man/man4/rc.4.gz OLD_FILES+=usr/share/man/man4/rp.4.gz # 20200721: sys/iommu.h moved to dev/iommu/ OLD_FILES+=usr/include/sys/iommu.h # 20200715: rework of devstat(9) man page OLD_FILES+=usr/share/man/man9/devstat_add_entry.9.gz # 20200714: update byacc to 20200330 OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_calc1.y OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_demo.y OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_destroy1.y OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_destroy2.y OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_destroy3.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit1.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit2.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit3.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit4.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit5.y OLD_FILES+=usr/tests/usr.bin/yacc/inherit0.y OLD_FILES+=usr/tests/usr.bin/yacc/inherit1.y OLD_FILES+=usr/tests/usr.bin/yacc/inherit2.y # 20200706: update of sglist(9), r360574 OLD_FILES+=usr/share/man/man9/sglist_append_ext_pgs.9.gz OLD_FILES+=usr/share/man/man9/sglist_append_mb_ext_pgs.9.gz OLD_FILES+=usr/share/man/man9/sglist_count_ext_pgs.9.gz OLD_FILES+=usr/share/man/man9/sglist_count_mb_ext_pgs.9.gz # 20200617: update opencsd to 0.14.2 OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_elem_etmv4d.h # 20200606: retire binutils build infrastructure OLD_FILES+=usr/bin/as OLD_FILES+=usr/bin/ld.bfd OLD_FILES+=usr/share/man/man1/as.1.gz OLD_FILES+=usr/share/man/man1/ld.bfd.1.gz OLD_FILES+=usr/share/man/man7/as.7.gz OLD_FILES+=usr/share/man/man7/ld.7.gz OLD_FILES+=usr/share/man/man7/ldint.7.gz OLD_FILES+=usr/share/man/man7/binutils.7.gz OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.x OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.x OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.x OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xbn OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xc OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xd OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xdc OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xdw OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xn OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xr OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xs OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xsc OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xsw OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xu OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xw OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.x OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xbn OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xc OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xd OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xdc OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xdw OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xn OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xr OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xs OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xsc OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xsw OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xu OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xw OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xw OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xw # 20200601: OpenSSL 32-bit compat engines moved to /usr/lib32/engines OLD_LIBS+=usr/lib32/capi.so OLD_LIBS+=usr/lib32/padlock.so # 20200528: libevent renamed libevent1 OLD_FILES+=usr/include/private/event/event.h OLD_DIRS+=usr/include/private/event OLD_FILES+=usr/lib/libprivateevent.a OLD_FILES+=usr/lib/libprivateevent.so OLD_LIBS+=usr/lib/libprivateevent.so.1 OLD_FILES+=usr/lib/libprivateevent_p.a # 20200523: new clang import which bumps version from 10.0.0 to 10.0.1 OLD_FILES+=usr/lib/clang/10.0.0/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/10.0.0/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/10.0.0/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/10.0.0/include/cuda_wrappers OLD_FILES+=usr/lib/clang/10.0.0/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/10.0.0/include/fuzzer OLD_FILES+=usr/lib/clang/10.0.0/include/openmp_wrappers/__clang_openmp_math.h OLD_FILES+=usr/lib/clang/10.0.0/include/openmp_wrappers/__clang_openmp_math_declares.h OLD_FILES+=usr/lib/clang/10.0.0/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/10.0.0/include/openmp_wrappers/math.h OLD_DIRS+=usr/lib/clang/10.0.0/include/openmp_wrappers OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/10.0.0/include/ppc_wrappers OLD_FILES+=usr/lib/clang/10.0.0/include/profile/InstrProfData.inc OLD_DIRS+=usr/lib/clang/10.0.0/include/profile OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/10.0.0/include/sanitizer OLD_FILES+=usr/lib/clang/10.0.0/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/10.0.0/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/10.0.0/include/xray OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/10.0.0/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/10.0.0/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/10.0.0/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/10.0.0/include/adxintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/altivec.h OLD_FILES+=usr/lib/clang/10.0.0/include/ammintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/arm64intr.h OLD_FILES+=usr/lib/clang/10.0.0/include/arm_acle.h OLD_FILES+=usr/lib/clang/10.0.0/include/arm_cmse.h OLD_FILES+=usr/lib/clang/10.0.0/include/arm_fp16.h OLD_FILES+=usr/lib/clang/10.0.0/include/arm_mve.h OLD_FILES+=usr/lib/clang/10.0.0/include/arm_neon.h OLD_FILES+=usr/lib/clang/10.0.0/include/armintr.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx2intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/avxintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/bmiintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/cetintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/clwbintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/clzerointrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/cpuid.h OLD_FILES+=usr/lib/clang/10.0.0/include/emmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/f16cintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/fma4intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/fmaintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/gfniintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/htmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/ia32intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/immintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/lwpintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/mm3dnow.h OLD_FILES+=usr/lib/clang/10.0.0/include/mm_malloc.h OLD_FILES+=usr/lib/clang/10.0.0/include/mmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/module.modulemap OLD_FILES+=usr/lib/clang/10.0.0/include/movdirintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/msa.h OLD_FILES+=usr/lib/clang/10.0.0/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/nmmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/10.0.0/include/opencl-c.h OLD_FILES+=usr/lib/clang/10.0.0/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/pkuintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/pmmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/popcntintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/rtmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/s390intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/sgxintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/shaintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/smmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/tbmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/tmmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/vadefs.h OLD_FILES+=usr/lib/clang/10.0.0/include/vaesintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/vecintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/wmmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/x86intrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/xmmintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/xopintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/10.0.0/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/10.0.0/include OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/10.0.0/lib/freebsd OLD_DIRS+=usr/lib/clang/10.0.0/lib OLD_DIRS+=usr/lib/clang/10.0.0 # 20200520: xform_userland.h removed OLD_FILES+=usr/include/crypto/xform_userland.h # 20200515: libalias cuseeme protocol support retired OLD_LIBS+=lib/libalias_cuseeme.so OLD_FILES+=usr/lib/libalias_cuseeme.a OLD_FILES+=usr/lib/libalias_cuseeme_p.a # 20200511: Remove deprecated crypto algorithms OLD_FILES+=usr/include/crypto/cast.h OLD_FILES+=usr/include/crypto/castsb.h OLD_FILES+=usr/include/crypto/skipjack.h # 20200511: Remove ubsec(4) OLD_FILES+=usr/share/man/man4/ubsec.4.gz # 20200428: route_var.h moved to net/route OLD_FILES+=usr/include/net/route_var.h # 20200418: Make libauditd private OLD_FILES+=usr/lib/libauditd.a OLD_FILES+=usr/lib/libauditd.so OLD_LIBS+=usr/lib/libauditd.so.5 OLD_FILES+=usr/lib/libauditd_p.a # 20200418: Remove bogus man links OLD_FILES+=usr/share/man/man3/getauusernam_R.3.gz OLD_FILES+=usr/share/man/man3/getauclassnam_3.3.gz # 20200414: NFS file handle affinity code for the NFS server re-organized OLD_FILES+=usr/include/nfs/nfs_fha.h # 20200401: Remove procfs-based process debugging OLD_FILES+=usr/include/sys/pioctl.h # 20200330: GDB_LIBEXEC option retired (always true) OLD_FILES+=usr/bin/gdb OLD_FILES+=usr/bin/gdbserver OLD_FILES+=usr/bin/kgdb OLD_FILES+=usr/share/man/man1/gdb.1.gz OLD_FILES+=usr/share/man/man1/gdbserver.1.gz OLD_FILES+=usr/share/man/man1/kgdb.1.gz # 20200327: OCF refactoring OLD_FILES+=usr/include/crypto/cryptosoft.h OLD_FILES+=usr/share/man/man9/crypto_find_driver.9.gz OLD_FILES+=usr/share/man/man9/crypto_register.9.gz OLD_FILES+=usr/share/man/man9/crypto_unregister.9.gz # 20200326: compat libs for libl are no longer built OLD_FILES+=usr/lib32/libfl.a OLD_FILES+=usr/lib32/libl.a OLD_FILES+=usr/lib32/libln.a # 20200323: INTERNALLIB don't install headers anymore OLD_FILES+=usr/include/libelftc.h OLD_FILES+=usr/include/libifconfig.h OLD_FILES+=usr/include/libpmcstat.h # 20200320: cx and ctau drivers retired OLD_FILES+=usr/share/man/man4/ctau.4.gz OLD_FILES+=usr/share/man/man4/cx.4.gz # 20200318: host.conf was deprecated a long time ago OLD_FILES+=etc/host.conf OLD_FILES+=etc/rc.d/nsswitch # 20200310: new clang import which bumps version from 9.0.1 to 10.0.0 OLD_FILES+=usr/lib/clang/9.0.1/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/9.0.1/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/9.0.1/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/9.0.1/include/cuda_wrappers OLD_FILES+=usr/lib/clang/9.0.1/include/openmp_wrappers/__clang_openmp_math.h OLD_FILES+=usr/lib/clang/9.0.1/include/openmp_wrappers/__clang_openmp_math_declares.h OLD_FILES+=usr/lib/clang/9.0.1/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/9.0.1/include/openmp_wrappers/math.h OLD_DIRS+=usr/lib/clang/9.0.1/include/openmp_wrappers OLD_FILES+=usr/lib/clang/9.0.1/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/9.0.1/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/9.0.1/include/ppc_wrappers OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/tsan_interface_atomic.h OLD_DIRS+=usr/lib/clang/9.0.1/include/sanitizer OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/9.0.1/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/9.0.1/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/9.0.1/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/9.0.1/include/adxintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/altivec.h OLD_FILES+=usr/lib/clang/9.0.1/include/ammintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/arm64intr.h OLD_FILES+=usr/lib/clang/9.0.1/include/arm_acle.h OLD_FILES+=usr/lib/clang/9.0.1/include/arm_fp16.h OLD_FILES+=usr/lib/clang/9.0.1/include/arm_neon.h OLD_FILES+=usr/lib/clang/9.0.1/include/armintr.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx2intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/avxintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/bmiintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/cetintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/clwbintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/clzerointrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/cpuid.h OLD_FILES+=usr/lib/clang/9.0.1/include/emmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/f16cintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/fma4intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/fmaintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/gfniintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/htmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/ia32intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/immintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/lwpintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/mm3dnow.h OLD_FILES+=usr/lib/clang/9.0.1/include/mm_malloc.h OLD_FILES+=usr/lib/clang/9.0.1/include/mmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/module.modulemap OLD_FILES+=usr/lib/clang/9.0.1/include/movdirintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/msa.h OLD_FILES+=usr/lib/clang/9.0.1/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/nmmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/9.0.1/include/opencl-c.h OLD_FILES+=usr/lib/clang/9.0.1/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/pkuintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/pmmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/popcntintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/rtmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/s390intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/sgxintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/shaintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/smmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/tbmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/tmmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/vadefs.h OLD_FILES+=usr/lib/clang/9.0.1/include/vaesintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/vecintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/wmmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/x86intrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/xmmintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/xopintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/9.0.1/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/9.0.1/include OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/9.0.1/lib/freebsd OLD_DIRS+=usr/lib/clang/9.0.1/lib OLD_DIRS+=usr/lib/clang/9.0.1 # 20200309: amd(8) retired OLD_FILES+=etc/amd.map OLD_FILES+=etc/newsyslog.conf.d/amd.conf OLD_FILES+=etc/rc.d/amd OLD_FILES+=usr/bin/pawd OLD_FILES+=usr/sbin/amd OLD_FILES+=usr/sbin/amq OLD_FILES+=usr/sbin/fixmount OLD_FILES+=usr/sbin/fsinfo OLD_FILES+=usr/sbin/hlfsd OLD_FILES+=usr/sbin/mk-amd-map OLD_FILES+=usr/sbin/wire-test OLD_FILES+=usr/share/examples/etc/amd.map OLD_FILES+=usr/share/man/man1/pawd.1.gz OLD_FILES+=usr/share/man/man5/amd.conf.5.gz OLD_FILES+=usr/share/man/man8/amd.8.gz OLD_FILES+=usr/share/man/man8/amq.8.gz OLD_FILES+=usr/share/man/man8/fixmount.8.gz OLD_FILES+=usr/share/man/man8/fsinfo.8.gz OLD_FILES+=usr/share/man/man8/hlfsd.8.gz OLD_FILES+=usr/share/man/man8/mk-amd-map.8.gz OLD_FILES+=usr/share/man/man8/wire-test.8.gz # 20200301: bktr removed OLD_DIRS+=usr/include/dev/bktr OLD_FILES+=usr/include/dev/bktr/ioctl_bktr.h OLD_FILES+=usr/include/dev/bktr/ioctl_bt848.h OLD_FILES+=usr/include/dev/bktr/ioctl_meteor.h .if ${TARGET_ARCH} == "i386" OLD_FILES+=usr/include/machine/ioctl_bktr.h OLD_FILES+=usr/include/machine/ioctl_meteor.h .endif OLD_FILES+=usr/share/man/man4/bktr.4.gz OLD_FILES+=usr/share/man/man4/brooktree.4.gz # 20200229: GCC 4.2.1 removed OLD_FILES+=usr/bin/g++ OLD_FILES+=usr/bin/gcc OLD_FILES+=usr/share/man/man1/g++.1.gz OLD_FILES+=usr/share/man/man1/gcc.1.gz OLD_FILES+=usr/bin/gcpp OLD_FILES+=usr/bin/gperf OLD_FILES+=usr/include/c++/4.2/algorithm OLD_FILES+=usr/include/c++/4.2/backward/algo.h OLD_FILES+=usr/include/c++/4.2/backward/algobase.h OLD_FILES+=usr/include/c++/4.2/backward/alloc.h OLD_FILES+=usr/include/c++/4.2/backward/backward_warning.h OLD_FILES+=usr/include/c++/4.2/backward/bvector.h OLD_FILES+=usr/include/c++/4.2/backward/complex.h OLD_FILES+=usr/include/c++/4.2/backward/defalloc.h OLD_FILES+=usr/include/c++/4.2/backward/deque.h OLD_FILES+=usr/include/c++/4.2/backward/fstream.h OLD_FILES+=usr/include/c++/4.2/backward/function.h OLD_FILES+=usr/include/c++/4.2/backward/hash_map.h OLD_FILES+=usr/include/c++/4.2/backward/hash_set.h OLD_FILES+=usr/include/c++/4.2/backward/hashtable.h OLD_FILES+=usr/include/c++/4.2/backward/heap.h OLD_FILES+=usr/include/c++/4.2/backward/iomanip.h OLD_FILES+=usr/include/c++/4.2/backward/iostream.h OLD_FILES+=usr/include/c++/4.2/backward/istream.h OLD_FILES+=usr/include/c++/4.2/backward/iterator.h OLD_FILES+=usr/include/c++/4.2/backward/list.h OLD_FILES+=usr/include/c++/4.2/backward/map.h OLD_FILES+=usr/include/c++/4.2/backward/multimap.h OLD_FILES+=usr/include/c++/4.2/backward/multiset.h OLD_FILES+=usr/include/c++/4.2/backward/new.h OLD_FILES+=usr/include/c++/4.2/backward/ostream.h OLD_FILES+=usr/include/c++/4.2/backward/pair.h OLD_FILES+=usr/include/c++/4.2/backward/queue.h OLD_FILES+=usr/include/c++/4.2/backward/rope.h OLD_FILES+=usr/include/c++/4.2/backward/set.h OLD_FILES+=usr/include/c++/4.2/backward/slist.h OLD_FILES+=usr/include/c++/4.2/backward/stack.h OLD_FILES+=usr/include/c++/4.2/backward/stream.h OLD_FILES+=usr/include/c++/4.2/backward/streambuf.h OLD_FILES+=usr/include/c++/4.2/backward/strstream OLD_FILES+=usr/include/c++/4.2/backward/tempbuf.h OLD_FILES+=usr/include/c++/4.2/backward/tree.h OLD_FILES+=usr/include/c++/4.2/backward/vector.h OLD_FILES+=usr/include/c++/4.2/bits/allocator.h OLD_FILES+=usr/include/c++/4.2/bits/atomic_word.h OLD_FILES+=usr/include/c++/4.2/bits/basic_file.h OLD_FILES+=usr/include/c++/4.2/bits/basic_ios.h OLD_FILES+=usr/include/c++/4.2/bits/basic_ios.tcc OLD_FILES+=usr/include/c++/4.2/bits/basic_string.h OLD_FILES+=usr/include/c++/4.2/bits/basic_string.tcc OLD_FILES+=usr/include/c++/4.2/bits/boost_concept_check.h OLD_FILES+=usr/include/c++/4.2/bits/c++allocator.h OLD_FILES+=usr/include/c++/4.2/bits/c++config.h OLD_FILES+=usr/include/c++/4.2/bits/c++io.h OLD_FILES+=usr/include/c++/4.2/bits/c++locale.h OLD_FILES+=usr/include/c++/4.2/bits/c++locale_internal.h OLD_FILES+=usr/include/c++/4.2/bits/char_traits.h OLD_FILES+=usr/include/c++/4.2/bits/cmath.tcc OLD_FILES+=usr/include/c++/4.2/bits/codecvt.h OLD_FILES+=usr/include/c++/4.2/bits/compatibility.h OLD_FILES+=usr/include/c++/4.2/bits/concept_check.h OLD_FILES+=usr/include/c++/4.2/bits/cpp_type_traits.h OLD_FILES+=usr/include/c++/4.2/bits/cpu_defines.h OLD_FILES+=usr/include/c++/4.2/bits/ctype_base.h OLD_FILES+=usr/include/c++/4.2/bits/ctype_inline.h OLD_FILES+=usr/include/c++/4.2/bits/ctype_noninline.h OLD_FILES+=usr/include/c++/4.2/bits/cxxabi_tweaks.h OLD_FILES+=usr/include/c++/4.2/bits/deque.tcc OLD_FILES+=usr/include/c++/4.2/bits/fstream.tcc OLD_FILES+=usr/include/c++/4.2/bits/functexcept.h OLD_FILES+=usr/include/c++/4.2/bits/gslice.h OLD_FILES+=usr/include/c++/4.2/bits/gslice_array.h OLD_FILES+=usr/include/c++/4.2/bits/gthr-default.h OLD_FILES+=usr/include/c++/4.2/bits/gthr-posix.h OLD_FILES+=usr/include/c++/4.2/bits/gthr-single.h OLD_FILES+=usr/include/c++/4.2/bits/gthr-tpf.h OLD_FILES+=usr/include/c++/4.2/bits/gthr.h OLD_FILES+=usr/include/c++/4.2/bits/indirect_array.h OLD_FILES+=usr/include/c++/4.2/bits/ios_base.h OLD_FILES+=usr/include/c++/4.2/bits/istream.tcc OLD_FILES+=usr/include/c++/4.2/bits/list.tcc OLD_FILES+=usr/include/c++/4.2/bits/locale_classes.h OLD_FILES+=usr/include/c++/4.2/bits/locale_facets.h OLD_FILES+=usr/include/c++/4.2/bits/locale_facets.tcc OLD_FILES+=usr/include/c++/4.2/bits/localefwd.h OLD_FILES+=usr/include/c++/4.2/bits/mask_array.h OLD_FILES+=usr/include/c++/4.2/bits/messages_members.h OLD_FILES+=usr/include/c++/4.2/bits/os_defines.h OLD_FILES+=usr/include/c++/4.2/bits/ostream.tcc OLD_FILES+=usr/include/c++/4.2/bits/ostream_insert.h OLD_FILES+=usr/include/c++/4.2/bits/postypes.h OLD_FILES+=usr/include/c++/4.2/bits/slice_array.h OLD_FILES+=usr/include/c++/4.2/bits/sstream.tcc OLD_FILES+=usr/include/c++/4.2/bits/stl_algo.h OLD_FILES+=usr/include/c++/4.2/bits/stl_algobase.h OLD_FILES+=usr/include/c++/4.2/bits/stl_bvector.h OLD_FILES+=usr/include/c++/4.2/bits/stl_construct.h OLD_FILES+=usr/include/c++/4.2/bits/stl_deque.h OLD_FILES+=usr/include/c++/4.2/bits/stl_function.h OLD_FILES+=usr/include/c++/4.2/bits/stl_heap.h OLD_FILES+=usr/include/c++/4.2/bits/stl_iterator.h OLD_FILES+=usr/include/c++/4.2/bits/stl_iterator_base_funcs.h OLD_FILES+=usr/include/c++/4.2/bits/stl_iterator_base_types.h OLD_FILES+=usr/include/c++/4.2/bits/stl_list.h OLD_FILES+=usr/include/c++/4.2/bits/stl_map.h OLD_FILES+=usr/include/c++/4.2/bits/stl_multimap.h OLD_FILES+=usr/include/c++/4.2/bits/stl_multiset.h OLD_FILES+=usr/include/c++/4.2/bits/stl_numeric.h OLD_FILES+=usr/include/c++/4.2/bits/stl_pair.h OLD_FILES+=usr/include/c++/4.2/bits/stl_queue.h OLD_FILES+=usr/include/c++/4.2/bits/stl_raw_storage_iter.h OLD_FILES+=usr/include/c++/4.2/bits/stl_relops.h OLD_FILES+=usr/include/c++/4.2/bits/stl_set.h OLD_FILES+=usr/include/c++/4.2/bits/stl_stack.h OLD_FILES+=usr/include/c++/4.2/bits/stl_tempbuf.h OLD_FILES+=usr/include/c++/4.2/bits/stl_tree.h OLD_FILES+=usr/include/c++/4.2/bits/stl_uninitialized.h OLD_FILES+=usr/include/c++/4.2/bits/stl_vector.h OLD_FILES+=usr/include/c++/4.2/bits/stream_iterator.h OLD_FILES+=usr/include/c++/4.2/bits/streambuf.tcc OLD_FILES+=usr/include/c++/4.2/bits/streambuf_iterator.h OLD_FILES+=usr/include/c++/4.2/bits/stringfwd.h OLD_FILES+=usr/include/c++/4.2/bits/time_members.h OLD_FILES+=usr/include/c++/4.2/bits/valarray_after.h OLD_FILES+=usr/include/c++/4.2/bits/valarray_array.h OLD_FILES+=usr/include/c++/4.2/bits/valarray_array.tcc OLD_FILES+=usr/include/c++/4.2/bits/valarray_before.h OLD_FILES+=usr/include/c++/4.2/bits/vector.tcc OLD_FILES+=usr/include/c++/4.2/bitset OLD_FILES+=usr/include/c++/4.2/cassert OLD_FILES+=usr/include/c++/4.2/cctype OLD_FILES+=usr/include/c++/4.2/cerrno OLD_FILES+=usr/include/c++/4.2/cfloat OLD_FILES+=usr/include/c++/4.2/ciso646 OLD_FILES+=usr/include/c++/4.2/climits OLD_FILES+=usr/include/c++/4.2/clocale OLD_FILES+=usr/include/c++/4.2/cmath OLD_FILES+=usr/include/c++/4.2/complex OLD_FILES+=usr/include/c++/4.2/csetjmp OLD_FILES+=usr/include/c++/4.2/csignal OLD_FILES+=usr/include/c++/4.2/cstdarg OLD_FILES+=usr/include/c++/4.2/cstddef OLD_FILES+=usr/include/c++/4.2/cstdio OLD_FILES+=usr/include/c++/4.2/cstdlib OLD_FILES+=usr/include/c++/4.2/cstring OLD_FILES+=usr/include/c++/4.2/ctime OLD_FILES+=usr/include/c++/4.2/cwchar OLD_FILES+=usr/include/c++/4.2/cwctype OLD_FILES+=usr/include/c++/4.2/cxxabi.h OLD_FILES+=usr/include/c++/4.2/debug/bitset OLD_FILES+=usr/include/c++/4.2/debug/debug.h OLD_FILES+=usr/include/c++/4.2/debug/deque OLD_FILES+=usr/include/c++/4.2/debug/formatter.h OLD_FILES+=usr/include/c++/4.2/debug/functions.h OLD_FILES+=usr/include/c++/4.2/debug/hash_map OLD_FILES+=usr/include/c++/4.2/debug/hash_map.h OLD_FILES+=usr/include/c++/4.2/debug/hash_multimap.h OLD_FILES+=usr/include/c++/4.2/debug/hash_multiset.h OLD_FILES+=usr/include/c++/4.2/debug/hash_set OLD_FILES+=usr/include/c++/4.2/debug/hash_set.h OLD_FILES+=usr/include/c++/4.2/debug/list OLD_FILES+=usr/include/c++/4.2/debug/macros.h OLD_FILES+=usr/include/c++/4.2/debug/map OLD_FILES+=usr/include/c++/4.2/debug/map.h OLD_FILES+=usr/include/c++/4.2/debug/multimap.h OLD_FILES+=usr/include/c++/4.2/debug/multiset.h OLD_FILES+=usr/include/c++/4.2/debug/safe_base.h OLD_FILES+=usr/include/c++/4.2/debug/safe_iterator.h OLD_FILES+=usr/include/c++/4.2/debug/safe_iterator.tcc OLD_FILES+=usr/include/c++/4.2/debug/safe_sequence.h OLD_FILES+=usr/include/c++/4.2/debug/set OLD_FILES+=usr/include/c++/4.2/debug/set.h OLD_FILES+=usr/include/c++/4.2/debug/string OLD_FILES+=usr/include/c++/4.2/debug/vector OLD_FILES+=usr/include/c++/4.2/deque OLD_FILES+=usr/include/c++/4.2/exception OLD_FILES+=usr/include/c++/4.2/exception_defines.h OLD_FILES+=usr/include/c++/4.2/ext/algorithm OLD_FILES+=usr/include/c++/4.2/ext/array_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/atomicity.h OLD_FILES+=usr/include/c++/4.2/ext/bitmap_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/codecvt_specializations.h OLD_FILES+=usr/include/c++/4.2/ext/concurrence.h OLD_FILES+=usr/include/c++/4.2/ext/debug_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/functional OLD_FILES+=usr/include/c++/4.2/ext/hash_fun.h OLD_FILES+=usr/include/c++/4.2/ext/hash_map OLD_FILES+=usr/include/c++/4.2/ext/hash_set OLD_FILES+=usr/include/c++/4.2/ext/hashtable.h OLD_FILES+=usr/include/c++/4.2/ext/iterator OLD_FILES+=usr/include/c++/4.2/ext/malloc_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/memory OLD_FILES+=usr/include/c++/4.2/ext/mt_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/new_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/numeric OLD_FILES+=usr/include/c++/4.2/ext/numeric_traits.h OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/assoc_container.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy/basic_tree_policy_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy/null_node_metadata.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_types.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/cond_dtor_entry_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/cond_key_dtor_entry_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/node_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/point_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/r_erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/binary_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/const_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/const_point_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/entry_cmp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/entry_pred.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/resize_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_/binomial_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/binomial_heap_base_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/cc_ht_map_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/cmp_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/cond_key_dtor_entry_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/debug_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/debug_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/entry_list_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/erase_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/erase_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/find_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/insert_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/insert_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/resize_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/resize_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/resize_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/size_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/standard_policies.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cond_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/container_base_dispatch.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/eq_fn/eq_by_less.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/eq_fn/hash_eq_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/constructor_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/constructor_destructor_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/constructor_destructor_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/debug_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/debug_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/erase_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/erase_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/find_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/find_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/gp_ht_map_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/insert_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/insert_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/iterator_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/resize_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/resize_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/resize_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/standard_policies.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/direct_mask_range_hashing_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/direct_mod_range_hashing_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/linear_probe_fn_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/mask_based_range_hashing.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/mod_based_range_hashing.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/probe_fn_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/quadratic_probe_fn_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/ranged_hash_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/ranged_probe_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_probe_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_range_hashing.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_ranged_hash_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_ranged_probe_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/const_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/const_point_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/left_child_next_sibling_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/node.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/null_metadata.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/constructor_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/entry_metadata_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/lu_map_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/counter_lu_metadata.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/counter_lu_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/mtf_lu_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/sample_update_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/map_debug_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/cond_dtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/node_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/ov_tree_map_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/pairing_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/child_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/cond_dtor_entry_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/const_child_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/head.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/insert_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/internal_node.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/leaf.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/node_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/node_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/node_metadata_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/pat_trie_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/point_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/r_erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/rotate_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/split_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/split_join_branch_bag.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/synth_e_access_traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/update_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/priority_queue_base_dispatch.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/node.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/rb_tree_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/rc.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/rc_binomial_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/cc_hash_max_collision_check_resize_trigger_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_exponential_size_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_size_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_prime_size_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_standard_resize_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/sample_resize_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/sample_resize_trigger.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/sample_size_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/node.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/splay_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/splay_tree_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/standard_policies.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/thin_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/node_metadata_selector.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/null_node_update_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/order_statistics_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/sample_tree_node_update.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_trace_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/node_metadata_selector.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/null_node_update_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/order_statistics_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/prefix_search_node_update_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/sample_trie_e_access_traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/sample_trie_node_update.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/string_trie_e_access_traits_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/trie_policy_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/type_utils.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/types_traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/const_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/const_point_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/point_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/exception.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/hash_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/list_update_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/priority_queue.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/tag_and_trait.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/tree_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/trie_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pod_char_traits.h OLD_FILES+=usr/include/c++/4.2/ext/pool_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/rb_tree OLD_FILES+=usr/include/c++/4.2/ext/rc_string_base.h OLD_FILES+=usr/include/c++/4.2/ext/rope OLD_FILES+=usr/include/c++/4.2/ext/ropeimpl.h OLD_FILES+=usr/include/c++/4.2/ext/slist OLD_FILES+=usr/include/c++/4.2/ext/sso_string_base.h OLD_FILES+=usr/include/c++/4.2/ext/stdio_filebuf.h OLD_FILES+=usr/include/c++/4.2/ext/stdio_sync_filebuf.h OLD_FILES+=usr/include/c++/4.2/ext/throw_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/type_traits.h OLD_FILES+=usr/include/c++/4.2/ext/typelist.h OLD_FILES+=usr/include/c++/4.2/ext/vstring.h OLD_FILES+=usr/include/c++/4.2/ext/vstring.tcc OLD_FILES+=usr/include/c++/4.2/ext/vstring_fwd.h OLD_FILES+=usr/include/c++/4.2/ext/vstring_util.h OLD_FILES+=usr/include/c++/4.2/fstream OLD_FILES+=usr/include/c++/4.2/functional OLD_FILES+=usr/include/c++/4.2/iomanip OLD_FILES+=usr/include/c++/4.2/ios OLD_FILES+=usr/include/c++/4.2/iosfwd OLD_FILES+=usr/include/c++/4.2/iostream OLD_FILES+=usr/include/c++/4.2/istream OLD_FILES+=usr/include/c++/4.2/iterator OLD_FILES+=usr/include/c++/4.2/limits OLD_FILES+=usr/include/c++/4.2/list OLD_FILES+=usr/include/c++/4.2/locale OLD_FILES+=usr/include/c++/4.2/map OLD_FILES+=usr/include/c++/4.2/memory OLD_FILES+=usr/include/c++/4.2/new OLD_FILES+=usr/include/c++/4.2/numeric OLD_FILES+=usr/include/c++/4.2/ostream OLD_FILES+=usr/include/c++/4.2/queue OLD_FILES+=usr/include/c++/4.2/set OLD_FILES+=usr/include/c++/4.2/sstream OLD_FILES+=usr/include/c++/4.2/stack OLD_FILES+=usr/include/c++/4.2/stdexcept OLD_FILES+=usr/include/c++/4.2/streambuf OLD_FILES+=usr/include/c++/4.2/string OLD_FILES+=usr/include/c++/4.2/tr1/array OLD_FILES+=usr/include/c++/4.2/tr1/bind_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/bind_repeat.h OLD_FILES+=usr/include/c++/4.2/tr1/boost_shared_ptr.h OLD_FILES+=usr/include/c++/4.2/tr1/cctype OLD_FILES+=usr/include/c++/4.2/tr1/cfenv OLD_FILES+=usr/include/c++/4.2/tr1/cfloat OLD_FILES+=usr/include/c++/4.2/tr1/cinttypes OLD_FILES+=usr/include/c++/4.2/tr1/climits OLD_FILES+=usr/include/c++/4.2/tr1/cmath OLD_FILES+=usr/include/c++/4.2/tr1/common.h OLD_FILES+=usr/include/c++/4.2/tr1/complex OLD_FILES+=usr/include/c++/4.2/tr1/cstdarg OLD_FILES+=usr/include/c++/4.2/tr1/cstdbool OLD_FILES+=usr/include/c++/4.2/tr1/cstdint OLD_FILES+=usr/include/c++/4.2/tr1/cstdio OLD_FILES+=usr/include/c++/4.2/tr1/cstdlib OLD_FILES+=usr/include/c++/4.2/tr1/ctgmath OLD_FILES+=usr/include/c++/4.2/tr1/ctime OLD_FILES+=usr/include/c++/4.2/tr1/ctype.h OLD_FILES+=usr/include/c++/4.2/tr1/cwchar OLD_FILES+=usr/include/c++/4.2/tr1/cwctype OLD_FILES+=usr/include/c++/4.2/tr1/fenv.h OLD_FILES+=usr/include/c++/4.2/tr1/float.h OLD_FILES+=usr/include/c++/4.2/tr1/functional OLD_FILES+=usr/include/c++/4.2/tr1/functional_hash.h OLD_FILES+=usr/include/c++/4.2/tr1/functional_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/hashtable OLD_FILES+=usr/include/c++/4.2/tr1/hashtable_policy.h OLD_FILES+=usr/include/c++/4.2/tr1/inttypes.h OLD_FILES+=usr/include/c++/4.2/tr1/limits.h OLD_FILES+=usr/include/c++/4.2/tr1/math.h OLD_FILES+=usr/include/c++/4.2/tr1/memory OLD_FILES+=usr/include/c++/4.2/tr1/mu_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/random OLD_FILES+=usr/include/c++/4.2/tr1/random.tcc OLD_FILES+=usr/include/c++/4.2/tr1/ref_fwd.h OLD_FILES+=usr/include/c++/4.2/tr1/ref_wrap_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/repeat.h OLD_FILES+=usr/include/c++/4.2/tr1/stdarg.h OLD_FILES+=usr/include/c++/4.2/tr1/stdbool.h OLD_FILES+=usr/include/c++/4.2/tr1/stdint.h OLD_FILES+=usr/include/c++/4.2/tr1/stdio.h OLD_FILES+=usr/include/c++/4.2/tr1/stdlib.h OLD_FILES+=usr/include/c++/4.2/tr1/tgmath.h OLD_FILES+=usr/include/c++/4.2/tr1/tuple OLD_FILES+=usr/include/c++/4.2/tr1/tuple_defs.h OLD_FILES+=usr/include/c++/4.2/tr1/tuple_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/type_traits OLD_FILES+=usr/include/c++/4.2/tr1/type_traits_fwd.h OLD_FILES+=usr/include/c++/4.2/tr1/unordered_map OLD_FILES+=usr/include/c++/4.2/tr1/unordered_set OLD_FILES+=usr/include/c++/4.2/tr1/utility OLD_FILES+=usr/include/c++/4.2/tr1/wchar.h OLD_FILES+=usr/include/c++/4.2/tr1/wctype.h OLD_FILES+=usr/include/c++/4.2/typeinfo OLD_FILES+=usr/include/c++/4.2/utility OLD_FILES+=usr/include/c++/4.2/valarray OLD_FILES+=usr/include/c++/4.2/vector .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386" OLD_FILES+=usr/include/gcc/4.2/__wmmintrin_aes.h OLD_FILES+=usr/include/gcc/4.2/__wmmintrin_pclmul.h OLD_FILES+=usr/include/gcc/4.2/ammintrin.h OLD_FILES+=usr/include/gcc/4.2/emmintrin.h OLD_FILES+=usr/include/gcc/4.2/mm3dnow.h OLD_FILES+=usr/include/gcc/4.2/mm_malloc.h OLD_FILES+=usr/include/gcc/4.2/mmintrin.h OLD_FILES+=usr/include/gcc/4.2/pmmintrin.h OLD_FILES+=usr/include/gcc/4.2/tmmintrin.h OLD_FILES+=usr/include/gcc/4.2/wmmintrin.h OLD_FILES+=usr/include/gcc/4.2/xmmintrin.h .elif ${TARGET_ARCH} == "arm" OLD_FILES+=usr/include/gcc/4.2/mmintrin.h .elif ${TARGET_ARCH} == "powerpc" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/include/gcc/4.2/altivec.h OLD_FILES+=usr/include/gcc/4.2/ppc-asm.h OLD_FILES+=usr/include/gcc/4.2/spe.h .endif OLD_FILES+=usr/lib/libgcov.a OLD_FILES+=usr/lib/libgomp.a OLD_FILES+=usr/lib/libstdc++.a OLD_FILES+=usr/lib/libstdc++.so OLD_LIBS+=usr/lib/libstdc++.so.6 OLD_FILES+=usr/lib/libstdc++_p.a OLD_FILES+=usr/lib/libsupc++.a OLD_FILES+=usr/lib/libsupc++.so OLD_LIBS+=usr/lib/libsupc++.so.1 OLD_FILES+=usr/lib/libsupc++_p.a OLD_LIBS+=usr/lib/libgomp.so.1 OLD_FILES+=usr/lib/libgomp_p.a OLD_FILES+=usr/libexec/cc1 OLD_FILES+=usr/libexec/cc1plus OLD_FILES+=usr/share/man/man1/gcpp.1.gz OLD_FILES+=usr/share/man/man1/gperf.1.gz OLD_FILES+=usr/share/man/man7/gperf.7.gz OLD_DIRS+=usr/include/c++/4.2/tr1 OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/eq_fn OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_ OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds/detail OLD_DIRS+=usr/include/c++/4.2/ext/pb_ds OLD_DIRS+=usr/include/c++/4.2/ext OLD_DIRS+=usr/include/c++/4.2/debug OLD_DIRS+=usr/include/c++/4.2/bits OLD_DIRS+=usr/include/c++/4.2/backward OLD_DIRS+=usr/include/c++/4.2 OLD_DIRS+=usr/include/gcc/4.2 OLD_DIRS+=usr/include/gcc # 20200220: Upgrade of ncurses, shlib bumped to version 9 OLD_LIBS+=lib/libncurses.so.8 OLD_LIBS+=lib/libncursesw.so.8 # 20200206: Remove elf2aout OLD_FILES+=usr/bin/elf2aout OLD_FILES+=usr/share/man/man1/elf2aout.1.gz # 20200204: simple_httpd removed OLD_FILES+=usr/sbin/simple_httpd # 20200127: vpo removed OLD_FILES+=usr/include/dev/ppbus/vpoio.h OLD_FILES+=usr/share/man/man4/imm.4.gz OLD_FILES+=usr/share/man/man4/vpo.4.gz # 20200104: gcc libssp removed OLD_FILES+=usr/lib/libssp.a # 20191229: GEOM_SCHED class and gsched tool removed OLD_LIBS+=lib/geom/geom_sched.so OLD_FILES+=sbin/gsched OLD_FILES+=usr/share/man/man8/gsched.8.gz # 20191222: new clang import which bumps version from 9.0.0 to 9.0.1 OLD_FILES+=usr/lib/clang/9.0.0/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/9.0.0/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/9.0.0/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/9.0.0/include/cuda_wrappers OLD_FILES+=usr/lib/clang/9.0.0/include/openmp_wrappers/__clang_openmp_math.h OLD_FILES+=usr/lib/clang/9.0.0/include/openmp_wrappers/__clang_openmp_math_declares.h OLD_FILES+=usr/lib/clang/9.0.0/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/9.0.0/include/openmp_wrappers/math.h OLD_DIRS+=usr/lib/clang/9.0.0/include/openmp_wrappers OLD_FILES+=usr/lib/clang/9.0.0/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/9.0.0/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/9.0.0/include/ppc_wrappers OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/tsan_interface_atomic.h OLD_DIRS+=usr/lib/clang/9.0.0/include/sanitizer OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/9.0.0/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/9.0.0/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/9.0.0/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/9.0.0/include/adxintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/altivec.h OLD_FILES+=usr/lib/clang/9.0.0/include/ammintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/arm64intr.h OLD_FILES+=usr/lib/clang/9.0.0/include/arm_acle.h OLD_FILES+=usr/lib/clang/9.0.0/include/arm_fp16.h OLD_FILES+=usr/lib/clang/9.0.0/include/arm_neon.h OLD_FILES+=usr/lib/clang/9.0.0/include/armintr.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx2intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/avxintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/bmiintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/cetintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/clwbintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/clzerointrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/cpuid.h OLD_FILES+=usr/lib/clang/9.0.0/include/emmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/f16cintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/fma4intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/fmaintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/gfniintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/htmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/ia32intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/immintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/lwpintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/mm3dnow.h OLD_FILES+=usr/lib/clang/9.0.0/include/mm_malloc.h OLD_FILES+=usr/lib/clang/9.0.0/include/mmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/module.modulemap OLD_FILES+=usr/lib/clang/9.0.0/include/movdirintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/msa.h OLD_FILES+=usr/lib/clang/9.0.0/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/nmmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/9.0.0/include/opencl-c.h OLD_FILES+=usr/lib/clang/9.0.0/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/pkuintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/pmmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/popcntintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/rtmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/s390intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/sgxintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/shaintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/smmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/tbmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/tmmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/vadefs.h OLD_FILES+=usr/lib/clang/9.0.0/include/vaesintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/vecintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/wmmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/x86intrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/xmmintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/xopintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/9.0.0/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/9.0.0/include OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/9.0.0/lib/freebsd OLD_DIRS+=usr/lib/clang/9.0.0/lib OLD_DIRS+=usr/lib/clang/9.0.0 # 20191221: Update libpcap from 1.9.0 to 1.9.1 OLD_FILES+=usr/share/man/man3/pcap_set_immediate_mode.3.gz OLD_FILES+=usr/share/man/man3/pcap_set_protocol.3.gz # 20191214: Removal of sranddev(3) OLD_FILES+=usr/share/man/man3/sranddev.3.gz # 20191213: Renamed (BIT|CPU)_NAND to (BIT|CPU)_ANDNOT OLD_FILES+=usr/share/man/man9/BIT_NAND.9.gz OLD_FILES+=usr/share/man/man9/CPU_NAND.9.gz # 20191213: remove timeout(9) OLD_FILES+=usr/share/man/man9/callout_handle_init.9.gz OLD_FILES+=usr/share/man/man9/timeout.9.gz OLD_FILES+=usr/share/man/man9/untimeout.9.gz # 20191128: Removal of trm(4) OLD_FILES+=usr/share/man/man4/trm.4.gz # 20191121: Removal of sio(4) OLD_FILES+=usr/share/man/man4/sio.4.gz # 20191105: picobsd(8), et al, removed OLD_FILES+=usr/share/man/man8/picobsd.8.gz # 20191017: taskqueue_start_threads_pinned became taskqueue_start_threads_cpuset OLD_FILES+=usr/share/man/man9/taskqueue_start_threads_pinned.9.gz # 20191009: new clang import which bumps version from 8.0.1 to 9.0.0 OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/esan_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/tsan_interface_atomic.h OLD_DIRS+=usr/lib/clang/8.0.1/include/sanitizer OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/8.0.1/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/8.0.1/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/8.0.1/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/8.0.1/include/adxintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/altivec.h OLD_FILES+=usr/lib/clang/8.0.1/include/ammintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/arm64intr.h OLD_FILES+=usr/lib/clang/8.0.1/include/arm_acle.h OLD_FILES+=usr/lib/clang/8.0.1/include/arm_fp16.h OLD_FILES+=usr/lib/clang/8.0.1/include/arm_neon.h OLD_FILES+=usr/lib/clang/8.0.1/include/armintr.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx2intrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/avxintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/bmiintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/cetintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/clwbintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/clzerointrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/cpuid.h OLD_FILES+=usr/lib/clang/8.0.1/include/emmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/f16cintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/fma4intrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/fmaintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/gfniintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/htmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/ia32intrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/immintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/lwpintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/mm3dnow.h OLD_FILES+=usr/lib/clang/8.0.1/include/mm_malloc.h OLD_FILES+=usr/lib/clang/8.0.1/include/mmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/module.modulemap OLD_FILES+=usr/lib/clang/8.0.1/include/movdirintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/msa.h OLD_FILES+=usr/lib/clang/8.0.1/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/nmmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/opencl-c.h OLD_FILES+=usr/lib/clang/8.0.1/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/pkuintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/pmmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/popcntintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/rtmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/s390intrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/sgxintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/shaintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/smmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/tbmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/tmmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/vadefs.h OLD_FILES+=usr/lib/clang/8.0.1/include/vaesintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/vecintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/wmmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/x86intrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/xmmintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/xopintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/8.0.1/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/8.0.1/include OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_DIRS+=usr/lib/clang/8.0.1/lib/freebsd OLD_DIRS+=usr/lib/clang/8.0.1/lib OLD_DIRS+=usr/lib/clang/8.0.1 # 20191009: libc++ 9.0.0 removed some experimental files OLD_FILES+=usr/include/c++/v1/experimental/any OLD_FILES+=usr/include/c++/v1/experimental/chrono OLD_FILES+=usr/include/c++/v1/experimental/numeric OLD_FILES+=usr/include/c++/v1/experimental/optional OLD_FILES+=usr/include/c++/v1/experimental/ratio OLD_FILES+=usr/include/c++/v1/experimental/string_view OLD_FILES+=usr/include/c++/v1/experimental/system_error OLD_FILES+=usr/include/c++/v1/experimental/tuple OLD_FILES+=usr/lib/libc++fs.a # 20191003: Remove useless ZFS tests OLD_FILES+=usr/tests/sys/cddl/zfs/tests/cli_root/zpool_create/zpool_create_013_neg.ksh OLD_FILES+=usr/tests/sys/cddl/zfs/tests/cli_root/zpool_create/zpool_create_014_neg.ksh OLD_FILES+=usr/tests/sys/cddl/zfs/tests/cli_root/zpool_create/zpool_create_016_pos.ksh # 20190910: mklocale(1) and colldef(1) removed OLD_FILES+=usr/bin/mklocale OLD_FILES+=usr/share/man/man1/mklocale.1.gz OLD_FILES+=usr/bin/colldef OLD_FILES+=usr/share/man/man1/colldef.1.gz # 20190904: Remove boot1.efifat and gptboot.efifat (which never should have been) OLD_FILES+=boot/boot1.efifat OLD_FILES+=boot/gptboot.efifat # 20190903: pc-sysinstall(8) removed OLD_FILES+=usr/share/examples/pc-sysinstall/README OLD_FILES+=usr/share/examples/pc-sysinstall/pc-autoinstall.conf OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.fbsd-netinstall OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.geli OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.gmirror OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.netinstall OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.restore OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.rsync OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.upgrade OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.zfs OLD_FILES+=usr/share/man/man8/pc-sysinstall.8.gz OLD_FILES+=usr/share/pc-sysinstall/backend-partmanager/create-part.sh OLD_FILES+=usr/share/pc-sysinstall/backend-partmanager/delete-part.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-emulation.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-laptop.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-nics.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/disk-info.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/disk-list.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/disk-part.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/enable-net.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/get-packages.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-components.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-config.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-mirrors.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-packages.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-rsync-backups.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-tzones.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/query-langs.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/send-logs.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/setup-ssh-keys.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/set-mirror.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/sys-mem.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/test-live.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/test-netup.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/update-part-list.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/xkeyboard-layouts.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/xkeyboard-models.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/xkeyboard-variants.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-bsdlabel.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-cleanup.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-disk.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-extractimage.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-ftp.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-installcomponents.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-installpackages.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-localize.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-mountdisk.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-mountoptical.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-networking.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-newfs.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-parse.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-packages.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-runcommands.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-unmount.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-upgrade.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-users.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions.sh OLD_FILES+=usr/share/pc-sysinstall/backend/installimage.sh OLD_FILES+=usr/share/pc-sysinstall/backend/parseconfig.sh OLD_FILES+=usr/share/pc-sysinstall/backend/startautoinstall.sh OLD_FILES+=usr/share/pc-sysinstall/conf/avail-langs OLD_FILES+=usr/share/pc-sysinstall/conf/exclude-from-upgrade OLD_FILES+=usr/share/pc-sysinstall/conf/license/bsd-en.txt OLD_FILES+=usr/share/pc-sysinstall/conf/license/intel-en.txt OLD_FILES+=usr/share/pc-sysinstall/conf/license/nvidia-en.txt OLD_FILES+=usr/share/pc-sysinstall/conf/pc-sysinstall.conf OLD_FILES+=usr/share/pc-sysinstall/doc/help-disk-list OLD_FILES+=usr/share/pc-sysinstall/doc/help-disk-size OLD_FILES+=usr/share/pc-sysinstall/doc/help-index OLD_FILES+=usr/share/pc-sysinstall/doc/help-start-autoinstall OLD_FILES+=usr/sbin/pc-sysinstall OLD_DIRS+=usr/share/examples/pc-sysinstall OLD_DIRS+=usr/share/pc-sysinstall/backend OLD_DIRS+=usr/share/pc-sysinstall/backend-partmanager OLD_DIRS+=usr/share/pc-sysinstall/backend-query OLD_DIRS+=usr/share/pc-sysinstall/conf/license OLD_DIRS+=usr/share/pc-sysinstall/conf OLD_DIRS+=usr/share/pc-sysinstall/doc OLD_DIRS+=usr/share/pc-sysinstall # 20190825: zlib 1.0.4 removed from kernel OLD_FILES+=usr/include/sys/zlib.h OLD_FILES+=usr/include/sys/zutil.h # 20190817: pft_ping.py and sniffer.py moved to /usr/tests/sys/netpfil/common OLD_FILES+=usr/tests/sys/netpfil/pf/sniffer.py OLD_FILES+=usr/tests/sys/netpfil/pf/pft_ping.py # 20190816: dir.h removed from POSIX OLD_FILES+=usr/include/sys/dir.h # 20190813: deprecated GEOM classes removed OLD_FILES+=usr/share/man/man4/geom_fox.4.gz # 20190729: gzip'ed a.out support removed OLD_FILES+=usr/include/sys/inflate.h # 20190722: cap_random(3) removed OLD_LIBS+=lib/casper/libcap_random.so.1 OLD_FILES+=usr/include/casper/cap_random.h OLD_LIBS+=usr/lib/libcap_random.so OLD_FILES+=usr/share/man/man3/libcap_random.3.gz OLD_FILES+=usr/share/man/man3/cap_random.3.gz OLD_FILES+=usr/share/man/man3/cap_random_buf.3.gz # 20190708: vm_page_hold() and _unhold() removed OLD_FILES+=usr/share/man/man9/vm_page_hold.9.gz OLD_FILES+=usr/share/man/man9/vm_page_unhold.9.gz # 20190625: Remove NAND and NANDFS support OLD_FILES+=usr/share/man/man4/nand.4.gz OLD_FILES+=usr/share/man/man4/nandsim.4.gz # 20190618: sys/capability.h removed (sys/capsicum.h is the one to use) OLD_FILES+=usr/include/sys/capability.h # 20190615: sys/pwm.h renamed to dev/pwmc.h OLD_FILES+=usr/include/sys/pwm.h # 20190612: new clang import which bumps version from 8.0.0 to 8.0.1 OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/esan_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/tsan_interface_atomic.h OLD_DIRS+=usr/lib/clang/8.0.0/include/sanitizer OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/8.0.0/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/8.0.0/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/8.0.0/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/8.0.0/include/adxintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/altivec.h OLD_FILES+=usr/lib/clang/8.0.0/include/ammintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/arm64intr.h OLD_FILES+=usr/lib/clang/8.0.0/include/arm_acle.h OLD_FILES+=usr/lib/clang/8.0.0/include/arm_fp16.h OLD_FILES+=usr/lib/clang/8.0.0/include/arm_neon.h OLD_FILES+=usr/lib/clang/8.0.0/include/armintr.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx2intrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/avxintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/bmiintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/cetintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/clwbintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/clzerointrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/cpuid.h OLD_FILES+=usr/lib/clang/8.0.0/include/emmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/f16cintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/fma4intrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/fmaintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/gfniintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/htmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/ia32intrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/immintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/lwpintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/mm3dnow.h OLD_FILES+=usr/lib/clang/8.0.0/include/mm_malloc.h OLD_FILES+=usr/lib/clang/8.0.0/include/mmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/module.modulemap OLD_FILES+=usr/lib/clang/8.0.0/include/movdirintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/msa.h OLD_FILES+=usr/lib/clang/8.0.0/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/nmmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/opencl-c.h OLD_FILES+=usr/lib/clang/8.0.0/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/pkuintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/pmmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/popcntintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/rtmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/s390intrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/sgxintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/shaintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/smmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/tbmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/tmmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/vadefs.h OLD_FILES+=usr/lib/clang/8.0.0/include/vaesintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/vecintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/wmmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/x86intrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/xmmintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/xopintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/8.0.0/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/8.0.0/include OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_DIRS+=usr/lib/clang/8.0.0/lib/freebsd OLD_DIRS+=usr/lib/clang/8.0.0/lib OLD_DIRS+=usr/lib/clang/8.0.0 # 20190523: Remove obsolete kgzip and support files OLD_FILES+=usr/sbin/kgzip OLD_FILES+=usr/lib/kgzldr.o OLD_FILES+=usr/share/man/man8/kgzip.8.gz # 20190517: Remove obsolete 10 and 10/100 ethernet drivers OLD_FILES+=usr/share/man/man4/bm.4.gz OLD_FILES+=usr/share/man/man4/cs.4.gz OLD_FILES+=usr/share/man/man4/de.4.gz OLD_FILES+=usr/share/man/man4/if_de.4.gz OLD_FILES+=usr/share/man/man4/ed.4.gz OLD_FILES+=usr/share/man/man4/if_ed.4.gz OLD_FILES+=usr/share/man/man4/ep.4.gz OLD_FILES+=usr/share/man/man4/ex.4.gz OLD_FILES+=usr/share/man/man4/fe.4.gz OLD_FILES+=usr/share/man/man4/pcn.4.gz OLD_FILES+=usr/share/man/man4/if_pcn.4.gz OLD_FILES+=usr/share/man/man4/sf.4.gz OLD_FILES+=usr/share/man/man4/if_sf.4.gz OLD_FILES+=usr/share/man/man4/sn.4.gz OLD_FILES+=usr/share/man/man4/if_sn.4.gz OLD_FILES+=usr/share/man/man4/tl.4.gz OLD_FILES+=usr/share/man/man4/if_tl.4.gz OLD_FILES+=usr/share/man/man4/tx.4.gz OLD_FILES+=usr/share/man/man4/if_tx.4.gz OLD_FILES+=usr/share/man/man4/txp.4.gz OLD_FILES+=usr/share/man/man4/if_txp.4.gz OLD_FILES+=usr/share/man/man4/vx.4.gz OLD_FILES+=usr/share/man/man4/wb.4.gz OLD_FILES+=usr/share/man/man4/if_wb.4.gz OLD_FILES+=usr/share/man/man4/xe.4.gz OLD_FILES+=usr/share/man/man4/if_xe.4.gz # 20190513: libcap_sysctl interface change OLD_LIBS+=lib/casper/libcap_sysctl.so.1 # 20190509: tests/sys/opencrypto requires the net/py-dpkt package OLD_FILES+=usr/tests/sys/opencrypto/dpkt.py OLD_FILES+=usr/tests/sys/opencrypto/dpkt.pyc # 20190304: new libc++ import which bumps version from 7.0.1 to 8.0.0 OLD_FILES+=usr/include/c++/v1/experimental/dynarray # 20190304: new clang import which bumps version from 7.0.1 to 8.0.0 OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/esan_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/tsan_interface_atomic.h OLD_DIRS+=usr/lib/clang/7.0.1/include/sanitizer OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/7.0.1/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/7.0.1/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/7.0.1/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/7.0.1/include/adxintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/altivec.h OLD_FILES+=usr/lib/clang/7.0.1/include/ammintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/arm64intr.h OLD_FILES+=usr/lib/clang/7.0.1/include/arm_acle.h OLD_FILES+=usr/lib/clang/7.0.1/include/arm_fp16.h OLD_FILES+=usr/lib/clang/7.0.1/include/arm_neon.h OLD_FILES+=usr/lib/clang/7.0.1/include/armintr.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx2intrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/avxintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/bmiintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/cetintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/clwbintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/clzerointrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/cpuid.h OLD_FILES+=usr/lib/clang/7.0.1/include/emmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/f16cintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/fma4intrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/fmaintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/gfniintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/htmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/ia32intrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/immintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/lwpintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/mm3dnow.h OLD_FILES+=usr/lib/clang/7.0.1/include/mm_malloc.h OLD_FILES+=usr/lib/clang/7.0.1/include/mmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/module.modulemap OLD_FILES+=usr/lib/clang/7.0.1/include/movdirintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/msa.h OLD_FILES+=usr/lib/clang/7.0.1/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/nmmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/opencl-c.h OLD_FILES+=usr/lib/clang/7.0.1/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/pkuintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/pmmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/popcntintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/rtmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/s390intrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/sgxintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/shaintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/smmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/tbmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/tmmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/vadefs.h OLD_FILES+=usr/lib/clang/7.0.1/include/vaesintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/vecintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/wmmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/x86intrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/xmmintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/xopintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/7.0.1/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/7.0.1/include OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_DIRS+=usr/lib/clang/7.0.1/lib/freebsd OLD_DIRS+=usr/lib/clang/7.0.1/lib OLD_DIRS+=usr/lib/clang/7.0.1 # 20190227: rename seq.h to seqc.h OLD_FILES+=usr/include/sys/seq.h # 20190222: libifconfig made INTERNALLIB OLD_FILES+=usr/lib/libprivateifconfig.a OLD_FILES+=usr/lib/libprivateifconfig_p.a # 20190131: pfil(9) changed OLD_FILES+=usr/share/man/man9/pfil_hook_get.9.gz OLD_FILES+=usr/share/man/man9/pfil_rlock.9.gz OLD_FILES+=usr/share/man/man9/pfil_runlock.9.gz OLD_FILES+=usr/share/man/man9/pfil_wlock.9.gz OLD_FILES+=usr/share/man/man9/pfil_wunlock.9.gz # 20190126: adv(4) / adw(4) removal OLD_FILES+=usr/share/man/man4/adv.4.gz OLD_FILES+=usr/share/man/man4/adw.4.gz # 20190123: nonexistant cred_update_thread(9) removed OLD_FILES+=usr/share/man/man9/cred_update_thread.9.gz # 20190114: old pbuf allocator removed OLD_FILES+=usr/share/man/man9/getpbuf.9.gz OLD_FILES+=usr/share/man/man9/pbuf.9.gz OLD_FILES+=usr/share/man/man9/relpbuf.9.gz OLD_FILES+=usr/share/man/man9/trypbuf.9.gz # 20181219: ibcs removal OLD_FILES+=usr/share/examples/ibcs2/hello.uu OLD_FILES+=usr/share/examples/ibcs2/README OLD_DIRS+=usr/share/examples/ibcs2 # 20181215: Migration of CTM to ports OLD_FILES+=usr/sbin/ctm OLD_FILES+=usr/sbin/ctm_dequeue OLD_FILES+=usr/sbin/ctm_rmail OLD_FILES+=usr/sbin/ctm_smail OLD_FILES+=usr/share/man/man1/ctm.1.gz OLD_FILES+=usr/share/man/man1/ctm_dequeue.1.gz OLD_FILES+=usr/share/man/man1/ctm_rmail.1.gz OLD_FILES+=usr/share/man/man1/ctm_smail.1.gz OLD_FILES+=usr/share/man/man5/ctm.5.gz # 20181214: Remove timed files OLD_FILES+=etc/rc.d/timed OLD_FILES+=usr/sbin/timed OLD_FILES+=usr/sbin/timedc OLD_FILES+=usr/share/man/man8/timed.8.gz OLD_FILES+=usr/share/man/man8/timedc.8.gz # 20181211: new clang import which bumps version from 6.0.1 to 7.0.1 OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/esan_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/tsan_interface_atomic.h OLD_DIRS+=usr/lib/clang/6.0.1/include/sanitizer OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/6.0.1/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/6.0.1/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/6.0.1/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/6.0.1/include/adxintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/altivec.h OLD_FILES+=usr/lib/clang/6.0.1/include/ammintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/arm64intr.h OLD_FILES+=usr/lib/clang/6.0.1/include/arm_acle.h OLD_FILES+=usr/lib/clang/6.0.1/include/arm_neon.h OLD_FILES+=usr/lib/clang/6.0.1/include/armintr.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx2intrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/avxintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/bmiintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/cetintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/clwbintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/clzerointrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/cpuid.h OLD_FILES+=usr/lib/clang/6.0.1/include/emmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/f16cintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/fma4intrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/fmaintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/gfniintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/htmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/ia32intrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/immintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/lwpintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/mm3dnow.h OLD_FILES+=usr/lib/clang/6.0.1/include/mm_malloc.h OLD_FILES+=usr/lib/clang/6.0.1/include/mmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/module.modulemap OLD_FILES+=usr/lib/clang/6.0.1/include/msa.h OLD_FILES+=usr/lib/clang/6.0.1/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/nmmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/opencl-c.h OLD_FILES+=usr/lib/clang/6.0.1/include/pkuintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/pmmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/popcntintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/rtmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/s390intrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/shaintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/smmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/tbmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/tmmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/vadefs.h OLD_FILES+=usr/lib/clang/6.0.1/include/vaesintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/vecintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/wmmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/x86intrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/xmmintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/xopintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/6.0.1/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/6.0.1/include OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_DIRS+=usr/lib/clang/6.0.1/lib/freebsd OLD_DIRS+=usr/lib/clang/6.0.1/lib OLD_DIRS+=usr/lib/clang/6.0.1 # 20181116: Rename test file OLD_FILES+=usr/tests/sys/netinet/reuseport_lb # 20181113: libufs version bumped to 7 OLD_LIBS+=lib/libufs.so.6 # 20181112: Cleanup old libcap_dns OLD_LIBS+=lib/casper/libcap_dns.so.1 # 20181030: malloc_domain(9) KPI change OLD_FILES+=usr/share/man/man9/malloc_domain.9.gz # 20181026: joy(4) removal OLD_FILES+=usr/share/man/man4/joy.4.gz # 20181025: OpenSSL libraries version bump to avoid conflict with ports OLD_LIBS+=lib/libcrypto.so.9 OLD_LIBS+=usr/lib/libssl.so.9 # 20181022: aha(4) removal OLD_FILES+=usr/share/man/man4/aha.4.gz # 20181022: dpt(4) removal OLD_FILES+=usr/share/man/man4/dpt.4.gz # 20181022: ncr(4) removal OLD_FILES+=usr/share/man/man4/ncr.4.gz # 20181022: ncv(4) removal OLD_FILES+=usr/share/man/man4/ncv.4.gz # 20181022: nsp(4) removal OLD_FILES+=usr/share/man/man4/nsp.4.gz # 20181022: stg(4) removal OLD_FILES+=usr/share/man/man4/stg.4.gz # 20181021: mse(4) removal OLD_FILES+=usr/share/man/man4/mse.4.gz .include "tools/build/mk/OptionalObsoleteFiles.inc" diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index fe764e7c4ed7..d2282b3e5a80 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -1,2529 +1,2528 @@ .include PACKAGE= kernel-man MAN= accept_filter.9 \ accf_data.9 \ accf_dns.9 \ accf_http.9 \ accf_tls.9 \ acl.9 \ alq.9 \ altq.9 \ atomic.9 \ backlight.9 \ bhnd.9 \ bhnd_erom.9 \ bios.9 \ bitset.9 \ bpf.9 \ buf.9 \ buf_ring.9 \ BUF_ISLOCKED.9 \ BUF_LOCK.9 \ BUF_LOCKFREE.9 \ BUF_LOCKINIT.9 \ BUF_RECURSED.9 \ BUF_TIMELOCK.9 \ BUF_UNLOCK.9 \ bus_activate_resource.9 \ BUS_ADD_CHILD.9 \ bus_adjust_resource.9 \ bus_alloc_resource.9 \ bus_attach_children.9 \ BUS_BIND_INTR.9 \ bus_child_present.9 \ BUS_CHILD_DELETED.9 \ BUS_CHILD_DETACHED.9 \ BUS_CHILD_LOCATION.9 \ BUS_CHILD_PNPINFO.9 \ BUS_CONFIG_INTR.9 \ BUS_DESCRIBE_INTR.9 \ bus_dma.9 \ bus_generic_detach.9 \ bus_generic_new_pass.9 \ bus_generic_print_child.9 \ bus_generic_read_ivar.9 \ bus_generic_shutdown.9 \ BUS_GET_CPUS.9 \ BUS_GET_PROPERTY.9 \ bus_get_resource.9 \ BUS_HINTED_CHILD.9 \ bus_map_resource.9 \ BUS_NEW_PASS.9 \ BUS_PRINT_CHILD.9 \ BUS_READ_IVAR.9 \ BUS_RESCAN.9 \ bus_release_resource.9 \ bus_set_pass.9 \ bus_set_resource.9 \ BUS_SETUP_INTR.9 \ bus_space.9 \ byteorder.9 \ callout.9 \ casuword.9 \ cd.9 \ cdefs.9 \ cnv.9 \ condvar.9 \ config_intrhook.9 \ contigmalloc.9 \ copy.9 \ coredumper_register.9 \ counter.9 \ cpu_machdep.9 \ cpuset.9 \ cr_bsd_visible.9 \ cr_cansee.9 \ cr_canseejailproc.9 \ cr_canseeothergids.9 \ cr_canseeotheruids.9 \ critical_enter.9 \ crypto.9 \ crypto_buffer.9 \ crypto_driver.9 \ crypto_request.9 \ crypto_session.9 \ CTASSERT.9 \ DB_COMMAND.9 \ DECLARE_GEOM_CLASS.9 \ DECLARE_MODULE.9 \ DEFINE_IFUNC.9 \ DELAY.9 \ devclass.9 \ devclass_find.9 \ devclass_get_device.9 \ devclass_get_devices.9 \ devclass_get_drivers.9 \ devclass_get_maxunit.9 \ devclass_get_name.9 \ devclass_get_softc.9 \ dev_clone.9 \ devfs_set_cdevpriv.9 \ device.9 \ device_add_child.9 \ DEVICE_ATTACH.9 \ device_delete_child.9 \ device_delete_children.9 \ DEVICE_DETACH.9 \ device_enable.9 \ device_find_child.9 \ device_get_children.9 \ device_get_devclass.9 \ device_get_driver.9 \ device_get_ivars.9 \ device_get_name.9 \ device_get_parent.9 \ device_get_property.9 \ device_get_softc.9 \ device_get_state.9 \ device_get_sysctl.9 \ device_get_unit.9 \ DEVICE_IDENTIFY.9 \ device_printf.9 \ DEVICE_PROBE.9 \ device_probe_and_attach.9 \ device_quiet.9 \ device_set_desc.9 \ device_set_driver.9 \ device_set_flags.9 \ DEVICE_SHUTDOWN.9 \ DEV_MODULE.9 \ dev_refthread.9 \ devctl_notify.9 \ devctl_process_running.9 \ devctl_safe_quote_sb.9 \ devstat.9 \ devtoname.9 \ disk.9 \ dnv.9 \ domain.9 \ domainset.9 \ dpcpu.9 \ drbr.9 \ driver.9 \ DRIVER_MODULE.9 \ efirt.9 \ epoch.9 \ ether_gen_addr.9 \ EVENTHANDLER.9 \ eventtimers.9 \ extattr.9 \ fail.9 \ fdt_pinctrl.9 \ fetch.9 \ firmware.9 \ fpu_kern.9 \ g_access.9 \ g_attach.9 \ g_bio.9 \ g_consumer.9 \ g_data.9 \ get_cyclecount.9 \ getenv.9 \ getnewvnode.9 \ g_event.9 \ g_geom.9 \ g_provider.9 \ g_provider_by_name.9 \ groupmember.9 \ g_wither_geom.9 \ gone_in.9 \ hardclock.9 \ hash.9 \ hashinit.9 \ hexdump.9 \ hhook.9 \ hz.9 \ ieee80211.9 \ ieee80211_amrr.9 \ ieee80211_beacon.9 \ ieee80211_bmiss.9 \ ieee80211_crypto.9 \ ieee80211_ddb.9 \ ieee80211_input.9 \ ieee80211_node.9 \ ieee80211_output.9 \ ieee80211_proto.9 \ ieee80211_radiotap.9 \ ieee80211_regdomain.9 \ ieee80211_scan.9 \ ieee80211_vap.9 \ iflib.9 \ iflibdd.9 \ iflibdi.9 \ iflibtxrx.9 \ ifnet.9 \ inittodr.9 \ insmntque.9 \ intr_event.9 \ intro.9 \ kasan.9 \ KASSERT.9 \ kern_reboot.9 \ kern_testfrwk.9 \ kern_yield.9 \ kernacc.9 \ kernel_mount.9 \ khelp.9 \ kmsan.9 \ kobj.9 \ kproc.9 \ kqueue.9 \ kstack_contains.9 \ kthread.9 \ ktr.9 \ lock.9 \ locking.9 \ LOCK_PROFILING.9 \ mac.9 \ make_dev.9 \ malloc.9 \ mbchain.9 \ mbuf.9 \ mbuf_tags.9 \ mdchain.9 \ memcchr.9 \ memguard.9 \ microseq.9 \ microtime.9 \ microuptime.9 \ mi_switch.9 \ mod_cc.9 \ module.9 \ MODULE_DEPEND.9 \ MODULE_PNP_INFO.9 \ MODULE_VERSION.9 \ mtx_pool.9 \ mutex.9 \ namei.9 \ netisr.9 \ nv.9 \ nvmem.9 \ OF_child.9 \ OF_device_from_xref.9 \ OF_finddevice.9 \ OF_getprop.9 \ OF_node_from_xref.9 \ OF_package_to_path.9 \ ofw_bus_is_compatible.9 \ ofw_bus_status_okay.9 \ ofw_graph.9 \ osd.9 \ owll.9 \ own.9 \ panic.9 \ p_candebug.9 \ p_cansee.9 \ pci.9 \ PCI_IOV_ADD_VF.9 \ PCI_IOV_INIT.9 \ pci_iov_schema.9 \ PCI_IOV_UNINIT.9 \ pfil.9 \ pfind.9 \ pget.9 \ pgfind.9 \ PHOLD.9 \ physio.9 \ pmap.9 \ pmap_activate.9 \ pmap_clear_modify.9 \ pmap_copy.9 \ pmap_enter.9 \ pmap_extract.9 \ pmap_kextract.9 \ pmap_growkernel.9 \ pmap_init.9 \ pmap_is_modified.9 \ pmap_is_prefaultable.9 \ pmap_map.9 \ pmap_mincore.9 \ pmap_object_init_pt.9 \ pmap_page_exists_quick.9 \ pmap_page_init.9 \ pmap_pinit.9 \ pmap_protect.9 \ pmap_qenter.9 \ pmap_quick_enter_page.9 \ pmap_release.9 \ pmap_remove.9 \ pmap_resident_count.9 \ pmap_unwire.9 \ pmap_zero_page.9 \ printf.9 \ prison_check.9 \ priv.9 \ prng.9 \ proc_rwmem.9 \ pseudofs.9 \ psignal.9 \ pwmbus.9 \ random.9 \ random_harvest.9 \ ratecheck.9 \ redzone.9 \ refcount.9 \ regulator.9 \ resettodr.9 \ resource_int_value.9 \ rijndael.9 \ rman.9 \ rmlock.9 \ rtentry.9 \ runqueue.9 \ rwlock.9 \ sbuf.9 \ scheduler.9 \ SDT.9 \ securelevel_gt.9 \ selrecord.9 \ sema.9 \ seqc.9 \ sf_buf.9 \ sglist.9 \ shm_map.9 \ signal.9 \ sleep.9 \ sleepqueue.9 \ smr.9 \ socket.9 \ stack.9 \ store.9 \ style.9 \ style.lua.9 \ ${_superio.9} \ swi.9 \ sx.9 \ syscall_helper_register.9 \ SYSCALL_MODULE.9 \ sysctl.9 \ sysctl_add_oid.9 \ sysctl_ctx_init.9 \ SYSINIT.9 \ taskqueue.9 \ tcp_functions.9 \ thread_exit.9 \ time.9 \ tvtohz.9 \ ucred.9 \ uidinfo.9 \ uio.9 \ unr.9 \ vaccess.9 \ vaccess_acl_nfs4.9 \ vaccess_acl_posix1e.9 \ vflush.9 \ VFS.9 \ vfs_busy.9 \ VFS_CHECKEXP.9 \ vfsconf.9 \ VFS_FHTOVP.9 \ vfs_getnewfsid.9 \ vfs_getopt.9 \ vfs_getvfs.9 \ VFS_MOUNT.9 \ vfs_mountedfrom.9 \ VFS_QUOTACTL.9 \ VFS_ROOT.9 \ vfs_rootmountalloc.9 \ VFS_SET.9 \ VFS_STATFS.9 \ vfs_suser.9 \ VFS_SYNC.9 \ vfs_timestamp.9 \ vfs_unbusy.9 \ VFS_UNMOUNT.9 \ vfs_unmountall.9 \ VFS_VGET.9 \ vget.9 \ vgone.9 \ vhold.9 \ vinvalbuf.9 \ vm_fault_prefault.9 \ vm_map.9 \ vm_map_check_protection.9 \ vm_map_delete.9 \ vm_map_entry_resize_free.9 \ vm_map_find.9 \ vm_map_findspace.9 \ vm_map_inherit.9 \ vm_map_init.9 \ vm_map_insert.9 \ vm_map_lock.9 \ vm_map_lookup.9 \ vm_map_madvise.9 \ vm_map_max.9 \ vm_map_protect.9 \ vm_map_remove.9 \ vm_map_stack.9 \ vm_map_submap.9 \ vm_map_sync.9 \ vm_map_wire.9 \ vm_page_alloc.9 \ vm_page_bits.9 \ vm_page_busy.9 \ vm_page_deactivate.9 \ vm_page_dontneed.9 \ vm_page_aflag.9 \ vm_page_free.9 \ vm_page_grab.9 \ vm_page_insert.9 \ vm_page_lookup.9 \ vm_page_rename.9 \ vm_page_wire.9 \ vm_set_page_size.9 \ vmem.9 \ vn_deallocate.9 \ vn_fullpath.9 \ vn_isdisk.9 \ VNET.9 \ vnode.9 \ vnode_pager_setsize.9 \ vnode_pager_purge_range.9 \ VOP_ACCESS.9 \ VOP_ACLCHECK.9 \ VOP_ADVISE.9 \ VOP_ADVLOCK.9 \ VOP_ALLOCATE.9 \ VOP_ATTRIB.9 \ VOP_BMAP.9 \ VOP_BWRITE.9 \ VOP_COPY_FILE_RANGE.9 \ VOP_CREATE.9 \ VOP_DEALLOCATE.9 \ VOP_FSYNC.9 \ VOP_GETACL.9 \ VOP_GETEXTATTR.9 \ VOP_GETPAGES.9 \ VOP_INACTIVE.9 \ VOP_INOTIFY.9 \ VOP_IOCTL.9 \ VOP_LINK.9 \ VOP_LISTEXTATTR.9 \ VOP_LOCK.9 \ VOP_LOOKUP.9 \ VOP_OPENCLOSE.9 \ VOP_PATHCONF.9 \ VOP_PRINT.9 \ VOP_RDWR.9 \ VOP_READ_PGCACHE.9 \ VOP_READDIR.9 \ VOP_READLINK.9 \ VOP_REALLOCBLKS.9 \ VOP_REMOVE.9 \ VOP_RENAME.9 \ VOP_REVOKE.9 \ VOP_SETACL.9 \ VOP_SETEXTATTR.9 \ VOP_STRATEGY.9 \ VOP_VPTOCNP.9 \ VOP_VPTOFH.9 \ vref.9 \ vrefcnt.9 \ vrele.9 \ vslock.9 \ watchdog.9 \ zero_region.9 \ zone.9 MLINKS= accept_filter.9 accept_filt_add.9 \ accept_filter.9 accept_filt_del.9 \ accept_filter.9 accept_filt_generic_mod_event.9 \ accept_filter.9 accept_filt_get.9 MLINKS+=alq.9 ALQ.9 \ alq.9 alq_close.9 \ alq.9 alq_flush.9 \ alq.9 alq_get.9 \ alq.9 alq_getn.9 \ alq.9 alq_open.9 \ alq.9 alq_open_flags.9 \ alq.9 alq_post.9 \ alq.9 alq_post_flags.9 \ alq.9 alq_write.9 \ alq.9 alq_writen.9 MLINKS+=altq.9 ALTQ.9 MLINKS+=atomic.9 atomic_add.9 \ atomic.9 atomic_clear.9 \ atomic.9 atomic_cmpset.9 \ atomic.9 atomic_fcmpset.9 \ atomic.9 atomic_fetchadd.9 \ atomic.9 atomic_load.9 \ atomic.9 atomic_readandclear.9 \ atomic.9 atomic_set.9 \ atomic.9 atomic_store.9 \ atomic.9 atomic_subtract.9 \ atomic.9 atomic_swap.9 \ atomic.9 atomic_testandclear.9 \ atomic.9 atomic_testandset.9 \ atomic.9 atomic_thread_fence.9 MLINKS+=bhnd.9 BHND_MATCH_BOARD_TYPE.9 \ bhnd.9 BHND_MATCH_BOARD_VENDOR.9 \ bhnd.9 BHND_MATCH_CHIP_ID.9 \ bhnd.9 BHND_MATCH_CHIP_PKG.9 \ bhnd.9 BHND_MATCH_CHIP_REV.9 \ bhnd.9 BHND_MATCH_CORE_ID.9 \ bhnd.9 BHND_MATCH_CORE_VENDOR.9 \ bhnd.9 bhnd_activate_resource.9 \ bhnd.9 bhnd_alloc_pmu.9 \ bhnd.9 bhnd_alloc_resource.9 \ bhnd.9 bhnd_alloc_resource_any.9 \ bhnd.9 bhnd_alloc_resources.9 \ bhnd.9 bhnd_board_matches.9 \ bhnd.9 bhnd_bus_match_child.9 \ bhnd.9 bhnd_bus_read_1.9 \ bhnd.9 bhnd_bus_read_2.9 \ bhnd.9 bhnd_bus_read_4.9 \ bhnd.9 bhnd_bus_read_stream_1.9 \ bhnd.9 bhnd_bus_read_stream_2.9 \ bhnd.9 bhnd_bus_read_stream_4.9 \ bhnd.9 bhnd_bus_write_1.9 \ bhnd.9 bhnd_bus_write_2.9 \ bhnd.9 bhnd_bus_write_4.9 \ bhnd.9 bhnd_bus_write_stream_1.9 \ bhnd.9 bhnd_bus_write_stream_2.9 \ bhnd.9 bhnd_bus_write_stream_4.9 \ bhnd.9 bhnd_chip_matches.9 \ bhnd.9 bhnd_core_class.9 \ bhnd.9 bhnd_core_get_match_desc.9 \ bhnd.9 bhnd_core_matches.9 \ bhnd.9 bhnd_core_name.9 \ bhnd.9 bhnd_cores_equal.9 \ bhnd.9 bhnd_deactivate_resource.9 \ bhnd.9 bhnd_decode_port_rid.9 \ bhnd.9 bhnd_deregister_provider.9 \ bhnd.9 bhnd_device_lookup.9 \ bhnd.9 bhnd_device_matches.9 \ bhnd.9 bhnd_device_quirks.9 \ bhnd.9 bhnd_driver_get_erom_class.9 \ bhnd.9 bhnd_enable_clocks.9 \ bhnd.9 bhnd_find_core_class.9 \ bhnd.9 bhnd_find_core_name.9 \ bhnd.9 bhnd_format_chip_id.9 \ bhnd.9 bhnd_get_attach_type.9 \ bhnd.9 bhnd_get_chipid.9 \ bhnd.9 bhnd_get_class.9 \ bhnd.9 bhnd_get_clock_freq.9 \ bhnd.9 bhnd_get_clock_latency.9 \ bhnd.9 bhnd_get_core_index.9 \ bhnd.9 bhnd_get_core_info.9 \ bhnd.9 bhnd_get_core_unit.9 \ bhnd.9 bhnd_get_device.9 \ bhnd.9 bhnd_get_device_name.9 \ bhnd.9 bhnd_get_dma_translation.9 \ bhnd.9 bhnd_get_hwrev.9 \ bhnd.9 bhnd_get_intr_count.9 \ bhnd.9 bhnd_get_intr_ivec.9 \ bhnd.9 bhnd_get_port_count.9 \ bhnd.9 bhnd_get_port_rid.9 \ bhnd.9 bhnd_get_region_addr.9 \ bhnd.9 bhnd_get_region_count.9 \ bhnd.9 bhnd_get_vendor.9 \ bhnd.9 bhnd_get_vendor_name.9 \ bhnd.9 bhnd_hwrev_matches.9 \ bhnd.9 bhnd_is_hw_suspended.9 \ bhnd.9 bhnd_is_region_valid.9 \ bhnd.9 bhnd_map_intr.9 \ bhnd.9 bhnd_match_core.9 \ bhnd.9 bhnd_nvram_getvar.9 \ bhnd.9 bhnd_nvram_getvar_array.9 \ bhnd.9 bhnd_nvram_getvar_int.9 \ bhnd.9 bhnd_nvram_getvar_int16.9 \ bhnd.9 bhnd_nvram_getvar_int32.9 \ bhnd.9 bhnd_nvram_getvar_int8.9 \ bhnd.9 bhnd_nvram_getvar_str.9 \ bhnd.9 bhnd_nvram_getvar_uint.9 \ bhnd.9 bhnd_nvram_getvar_uint16.9 \ bhnd.9 bhnd_nvram_getvar_uint32.9 \ bhnd.9 bhnd_nvram_getvar_uint8.9 \ bhnd.9 bhnd_nvram_string_array_next.9 \ bhnd.9 bhnd_read_board_info.9 \ bhnd.9 bhnd_read_config.9 \ bhnd.9 bhnd_read_ioctl.9 \ bhnd.9 bhnd_read_iost.9 \ bhnd.9 bhnd_register_provider.9 \ bhnd.9 bhnd_release_ext_rsrc.9 \ bhnd.9 bhnd_release_pmu.9 \ bhnd.9 bhnd_release_provider.9 \ bhnd.9 bhnd_release_resource.9 \ bhnd.9 bhnd_release_resources.9 \ bhnd.9 bhnd_request_clock.9 \ bhnd.9 bhnd_request_ext_rsrc.9 \ bhnd.9 bhnd_reset_hw.9 \ bhnd.9 bhnd_retain_provider.9 \ bhnd.9 bhnd_set_custom_core_desc.9 \ bhnd.9 bhnd_set_default_core_desc.9 \ bhnd.9 bhnd_suspend_hw.9 \ bhnd.9 bhnd_unmap_intr.9 \ bhnd.9 bhnd_vendor_name.9 \ bhnd.9 bhnd_write_config.9 \ bhnd.9 bhnd_write_ioctl.9 MLINKS+=bhnd_erom.9 bhnd_erom_alloc.9 \ bhnd_erom.9 bhnd_erom_dump.9 \ bhnd_erom.9 bhnd_erom_fini_static.9 \ bhnd_erom.9 bhnd_erom_free.9 \ bhnd_erom.9 bhnd_erom_free_core_table.9 \ bhnd_erom.9 bhnd_erom_get_core_table.9 \ bhnd_erom.9 bhnd_erom_init_static.9 \ bhnd_erom.9 bhnd_erom_io.9 \ bhnd_erom.9 bhnd_erom_io_fini.9 \ bhnd_erom.9 bhnd_erom_io_map.9 \ bhnd_erom.9 bhnd_erom_io_read.9 \ bhnd_erom.9 bhnd_erom_iobus_init.9 \ bhnd_erom.9 bhnd_erom_iores_new.9 \ bhnd_erom.9 bhnd_erom_lookup_core.9 \ bhnd_erom.9 bhnd_erom_lookup_core_addr.9 \ bhnd_erom.9 bhnd_erom_probe.9 \ bhnd_erom.9 bhnd_erom_probe_driver_classes.9 MLINKS+=bitset.9 BITSET_DEFINE.9 \ bitset.9 BITSET_T_INITIALIZER.9 \ bitset.9 BITSET_FSET.9 \ bitset.9 BIT_CLR.9 \ bitset.9 BIT_COPY.9 \ bitset.9 BIT_ISSET.9 \ bitset.9 BIT_SET.9 \ bitset.9 BIT_ZERO.9 \ bitset.9 BIT_FILL.9 \ bitset.9 BIT_SETOF.9 \ bitset.9 BIT_EMPTY.9 \ bitset.9 BIT_ISFULLSET.9 \ bitset.9 BIT_FFS.9 \ bitset.9 BIT_FFS_AT.9 \ bitset.9 BIT_FLS.9 \ bitset.9 BIT_FOREACH_ISSET.9 \ bitset.9 BIT_FOREACH_ISCLR.9 \ bitset.9 BIT_COUNT.9 \ bitset.9 BIT_SUBSET.9 \ bitset.9 BIT_OVERLAP.9 \ bitset.9 BIT_CMP.9 \ bitset.9 BIT_OR.9 \ bitset.9 BIT_OR2.9 \ bitset.9 BIT_ORNOT.9 \ bitset.9 BIT_ORNOT2.9 \ bitset.9 BIT_AND.9 \ bitset.9 BIT_AND2.9 \ bitset.9 BIT_ANDNOT.9 \ bitset.9 BIT_ANDNOT2.9 \ bitset.9 BIT_XOR.9 \ bitset.9 BIT_XOR2.9 \ bitset.9 BIT_CLR_ATOMIC.9 \ bitset.9 BIT_SET_ATOMIC.9 \ bitset.9 BIT_SET_ATOMIC_ACQ.9 \ bitset.9 BIT_TEST_SET_ATOMIC.9 \ bitset.9 BIT_TEST_CLR_ATOMIC.9 \ bitset.9 BIT_AND_ATOMIC.9 \ bitset.9 BIT_OR_ATOMIC.9 \ bitset.9 BIT_COPY_STORE_REL.9 MLINKS+=bpf.9 bpfattach.9 \ bpf.9 bpfattach2.9 \ bpf.9 bpfdetach.9 \ bpf.9 bpf_filter.9 \ bpf.9 bpf_mtap.9 \ bpf.9 bpf_mtap2.9 \ bpf.9 bpf_tap.9 \ bpf.9 bpf_validate.9 MLINKS+=buf.9 bp.9 MLINKS+=buf_ring.9 buf_ring_alloc.9 \ buf_ring.9 buf_ring_free.9 \ buf_ring.9 buf_ring_enqueue.9 \ buf_ring.9 buf_ring_enqueue_bytes.9 \ buf_ring.9 buf_ring_dequeue_mc.9 \ buf_ring.9 buf_ring_dequeue_sc.9 \ buf_ring.9 buf_ring_count.9 \ buf_ring.9 buf_ring_empty.9 \ buf_ring.9 buf_ring_full.9 \ buf_ring.9 buf_ring_peek.9 MLINKS+=bus_activate_resource.9 bus_deactivate_resource.9 MLINKS+=bus_alloc_resource.9 bus_alloc_resource_any.9 MLINKS+=bus_attach_children.9 bus_delayed_attach_children.9 \ bus_attach_children.9 bus_detach_children.9 \ bus_attach_children.9 bus_enumerate_hinted_children.9 \ bus_attach_children.9 bus_identify_children.9 MLINKS+=BUS_BIND_INTR.9 bus_bind_intr.9 MLINKS+=BUS_CONFIG_INTR.9 bus_config_intr.9 MLINKS+=BUS_DESCRIBE_INTR.9 bus_describe_intr.9 MLINKS+=bus_dma.9 busdma.9 \ bus_dma.9 bus_dmamap_create.9 \ bus_dma.9 bus_dmamap_destroy.9 \ bus_dma.9 bus_dmamap_load.9 \ bus_dma.9 bus_dmamap_load_bio.9 \ bus_dma.9 bus_dmamap_load_ccb.9 \ bus_dma.9 bus_dmamap_load_crp.9 \ bus_dma.9 bus_dmamap_load_crp_buffer.9 \ bus_dma.9 bus_dmamap_load_mbuf.9 \ bus_dma.9 bus_dmamap_load_mbuf_sg.9 \ bus_dma.9 bus_dmamap_load_uio.9 \ bus_dma.9 bus_dmamap_sync.9 \ bus_dma.9 bus_dmamap_unload.9 \ bus_dma.9 bus_dmamem_alloc.9 \ bus_dma.9 bus_dmamem_free.9 \ bus_dma.9 bus_dma_tag_create.9 \ bus_dma.9 bus_dma_tag_destroy.9 MLINKS+=bus_generic_print_child.9 bus_print_child_domain.9 \ bus_generic_print_child.9 bus_print_child_footer.9 \ bus_generic_print_child.9 bus_print_child_header.9 MLINKS+=bus_generic_read_ivar.9 bus_generic_write_ivar.9 MLINKS+=BUS_GET_CPUS.9 bus_get_cpus.9 MLINKS+=bus_map_resource.9 bus_unmap_resource.9 \ bus_map_resource.9 resource_init_map_request.9 MLINKS+=BUS_READ_IVAR.9 BUS_WRITE_IVAR.9 MLINKS+=BUS_SETUP_INTR.9 bus_setup_intr.9 \ BUS_SETUP_INTR.9 BUS_TEARDOWN_INTR.9 \ BUS_SETUP_INTR.9 bus_teardown_intr.9 MLINKS+=bus_space.9 bus_space_alloc.9 \ bus_space.9 bus_space_barrier.9 \ bus_space.9 bus_space_copy_region_1.9 \ bus_space.9 bus_space_copy_region_2.9 \ bus_space.9 bus_space_copy_region_4.9 \ bus_space.9 bus_space_copy_region_8.9 \ bus_space.9 bus_space_copy_region_stream_1.9 \ bus_space.9 bus_space_copy_region_stream_2.9 \ bus_space.9 bus_space_copy_region_stream_4.9 \ bus_space.9 bus_space_copy_region_stream_8.9 \ bus_space.9 bus_space_free.9 \ bus_space.9 bus_space_map.9 \ bus_space.9 bus_space_peek_1.9 \ bus_space.9 bus_space_peek_2.9 \ bus_space.9 bus_space_peek_4.9 \ bus_space.9 bus_space_peek_8.9 \ bus_space.9 bus_space_poke_1.9 \ bus_space.9 bus_space_poke_2.9 \ bus_space.9 bus_space_poke_4.9 \ bus_space.9 bus_space_poke_8.9 \ bus_space.9 bus_space_read_1.9 \ bus_space.9 bus_space_read_2.9 \ bus_space.9 bus_space_read_4.9 \ bus_space.9 bus_space_read_8.9 \ bus_space.9 bus_space_read_multi_1.9 \ bus_space.9 bus_space_read_multi_2.9 \ bus_space.9 bus_space_read_multi_4.9 \ bus_space.9 bus_space_read_multi_8.9 \ bus_space.9 bus_space_read_multi_stream_1.9 \ bus_space.9 bus_space_read_multi_stream_2.9 \ bus_space.9 bus_space_read_multi_stream_4.9 \ bus_space.9 bus_space_read_multi_stream_8.9 \ bus_space.9 bus_space_read_region_1.9 \ bus_space.9 bus_space_read_region_2.9 \ bus_space.9 bus_space_read_region_4.9 \ bus_space.9 bus_space_read_region_8.9 \ bus_space.9 bus_space_read_region_stream_1.9 \ bus_space.9 bus_space_read_region_stream_2.9 \ bus_space.9 bus_space_read_region_stream_4.9 \ bus_space.9 bus_space_read_region_stream_8.9 \ bus_space.9 bus_space_read_stream_1.9 \ bus_space.9 bus_space_read_stream_2.9 \ bus_space.9 bus_space_read_stream_4.9 \ bus_space.9 bus_space_read_stream_8.9 \ bus_space.9 bus_space_set_multi_1.9 \ bus_space.9 bus_space_set_multi_2.9 \ bus_space.9 bus_space_set_multi_4.9 \ bus_space.9 bus_space_set_multi_8.9 \ bus_space.9 bus_space_set_multi_stream_1.9 \ bus_space.9 bus_space_set_multi_stream_2.9 \ bus_space.9 bus_space_set_multi_stream_4.9 \ bus_space.9 bus_space_set_multi_stream_8.9 \ bus_space.9 bus_space_set_region_1.9 \ bus_space.9 bus_space_set_region_2.9 \ bus_space.9 bus_space_set_region_4.9 \ bus_space.9 bus_space_set_region_8.9 \ bus_space.9 bus_space_set_region_stream_1.9 \ bus_space.9 bus_space_set_region_stream_2.9 \ bus_space.9 bus_space_set_region_stream_4.9 \ bus_space.9 bus_space_set_region_stream_8.9 \ bus_space.9 bus_space_subregion.9 \ bus_space.9 bus_space_unmap.9 \ bus_space.9 bus_space_write_1.9 \ bus_space.9 bus_space_write_2.9 \ bus_space.9 bus_space_write_4.9 \ bus_space.9 bus_space_write_8.9 \ bus_space.9 bus_space_write_multi_1.9 \ bus_space.9 bus_space_write_multi_2.9 \ bus_space.9 bus_space_write_multi_4.9 \ bus_space.9 bus_space_write_multi_8.9 \ bus_space.9 bus_space_write_multi_stream_1.9 \ bus_space.9 bus_space_write_multi_stream_2.9 \ bus_space.9 bus_space_write_multi_stream_4.9 \ bus_space.9 bus_space_write_multi_stream_8.9 \ bus_space.9 bus_space_write_region_1.9 \ bus_space.9 bus_space_write_region_2.9 \ bus_space.9 bus_space_write_region_4.9 \ bus_space.9 bus_space_write_region_8.9 \ bus_space.9 bus_space_write_region_stream_1.9 \ bus_space.9 bus_space_write_region_stream_2.9 \ bus_space.9 bus_space_write_region_stream_4.9 \ bus_space.9 bus_space_write_region_stream_8.9 \ bus_space.9 bus_space_write_stream_1.9 \ bus_space.9 bus_space_write_stream_2.9 \ bus_space.9 bus_space_write_stream_4.9 \ bus_space.9 bus_space_write_stream_8.9 MLINKS+=byteorder.9 be16dec.9 \ byteorder.9 be16enc.9 \ byteorder.9 be16toh.9 \ byteorder.9 be32dec.9 \ byteorder.9 be32enc.9 \ byteorder.9 be32toh.9 \ byteorder.9 be64dec.9 \ byteorder.9 be64enc.9 \ byteorder.9 be64toh.9 \ byteorder.9 bswap16.9 \ byteorder.9 bswap32.9 \ byteorder.9 bswap64.9 \ byteorder.9 htobe16.9 \ byteorder.9 htobe32.9 \ byteorder.9 htobe64.9 \ byteorder.9 htole16.9 \ byteorder.9 htole32.9 \ byteorder.9 htole64.9 \ byteorder.9 le16dec.9 \ byteorder.9 le16enc.9 \ byteorder.9 le16toh.9 \ byteorder.9 le32dec.9 \ byteorder.9 le32enc.9 \ byteorder.9 le32toh.9 \ byteorder.9 le64dec.9 \ byteorder.9 le64enc.9 \ byteorder.9 le64toh.9 MLINKS+=callout.9 callout_active.9 \ callout.9 callout_deactivate.9 \ callout.9 callout_drain.9 \ callout.9 callout_init.9 \ callout.9 callout_init_mtx.9 \ callout.9 callout_init_rm.9 \ callout.9 callout_init_rw.9 \ callout.9 callout_pending.9 \ callout.9 callout_reset.9 \ callout.9 callout_reset_curcpu.9 \ callout.9 callout_reset_on.9 \ callout.9 callout_reset_sbt.9 \ callout.9 callout_reset_sbt_curcpu.9 \ callout.9 callout_reset_sbt_on.9 \ callout.9 callout_schedule.9 \ callout.9 callout_schedule_curcpu.9 \ callout.9 callout_schedule_on.9 \ callout.9 callout_schedule_sbt.9 \ callout.9 callout_schedule_sbt_curcpu.9 \ callout.9 callout_schedule_sbt_on.9 \ callout.9 callout_stop.9 \ callout.9 callout_when.9 MLINKS+=cnv.9 cnvlist.9 \ cnv.9 cnvlist_free_binary.9 \ cnv.9 cnvlist_free_bool.9 \ cnv.9 cnvlist_free_bool_array.9 \ cnv.9 cnvlist_free_descriptor.9 \ cnv.9 cnvlist_free_descriptor_array.9 \ cnv.9 cnvlist_free_null.9 \ cnv.9 cnvlist_free_number.9 \ cnv.9 cnvlist_free_number_array.9 \ cnv.9 cnvlist_free_nvlist.9 \ cnv.9 cnvlist_free_nvlist_array.9 \ cnv.9 cnvlist_free_string.9 \ cnv.9 cnvlist_free_string_array.9 \ cnv.9 cnvlist_get_binary.9 \ cnv.9 cnvlist_get_bool.9 \ cnv.9 cnvlist_get_bool_array.9 \ cnv.9 cnvlist_get_descriptor.9 \ cnv.9 cnvlist_get_descriptor_array.9 \ cnv.9 cnvlist_get_number.9 \ cnv.9 cnvlist_get_number_array.9 \ cnv.9 cnvlist_get_nvlist.9 \ cnv.9 cnvlist_get_nvlist_array.9 \ cnv.9 cnvlist_get_string.9 \ cnv.9 cnvlist_get_string_array.9 \ cnv.9 cnvlist_take_binary.9 \ cnv.9 cnvlist_take_bool.9 \ cnv.9 cnvlist_take_bool_array.9 \ cnv.9 cnvlist_take_descriptor.9 \ cnv.9 cnvlist_take_descriptor_array.9 \ cnv.9 cnvlist_take_number.9 \ cnv.9 cnvlist_take_number_array.9 \ cnv.9 cnvlist_take_nvlist.9 \ cnv.9 cnvlist_take_nvlist_array.9 \ cnv.9 cnvlist_take_string.9 \ cnv.9 cnvlist_take_string_array.9 MLINKS+=condvar.9 cv_broadcast.9 \ condvar.9 cv_broadcastpri.9 \ condvar.9 cv_destroy.9 \ condvar.9 cv_init.9 \ condvar.9 cv_signal.9 \ condvar.9 cv_timedwait.9 \ condvar.9 cv_timedwait_sig.9 \ condvar.9 cv_timedwait_sig_sbt.9 \ condvar.9 cv_wait.9 \ condvar.9 cv_wait_sig.9 \ condvar.9 cv_wait_unlock.9 \ condvar.9 cv_wmesg.9 MLINKS+=config_intrhook.9 config_intrhook_disestablish.9 \ config_intrhook.9 config_intrhook_drain.9 \ config_intrhook.9 config_intrhook_establish.9 \ config_intrhook.9 config_intrhook_oneshot.9 MLINKS+=contigmalloc.9 contigmalloc_domainset.9 MLINKS+=casuword.9 casueword.9 \ casuword.9 casueword32.9 \ casuword.9 casuword32.9 MLINKS+=copy.9 copyin.9 \ copy.9 copyin_nofault.9 \ copy.9 copyinstr.9 \ copy.9 copyout.9 \ copy.9 copyout_nofault.9 \ copy.9 copystr.9 MLINKS+=coredumper_register.9 coredumper_unregister.9 MLINKS+=counter.9 counter_u64_alloc.9 \ counter.9 counter_u64_free.9 \ counter.9 counter_u64_add.9 \ counter.9 counter_enter.9 \ counter.9 counter_exit.9 \ counter.9 counter_ratecheck.9 \ counter.9 counter_u64_add_protected.9 \ counter.9 counter_u64_fetch.9 \ counter.9 counter_u64_zero.9 \ counter.9 SYSCTL_COUNTER_U64.9 \ counter.9 SYSCTL_ADD_COUNTER_U64.9 \ counter.9 SYSCTL_COUNTER_U64_ARRAY.9 \ counter.9 SYSCTL_ADD_COUNTER_U64_ARRAY.9 MLINKS+=cpu_machdep.9 cpu_copy_thread.9 \ cpu_machdep.9 cpu_exec_vmspace_reuse.9 \ cpu_machdep.9 cpu_exit.9 \ cpu_machdep.9 cpu_fetch_syscall_args.9 \ cpu_machdep.9 cpu_fork.9 \ cpu_machdep.9 cpu_fork_kthread_handler.9 \ cpu_machdep.9 cpu_idle.9 \ cpu_machdep.9 cpu_idle_wakeup.9 \ cpu_machdep.9 cpu_procctl.9 \ cpu_machdep.9 cpu_ptrace.9 \ cpu_machdep.9 cpu_set_syscall_retval.9 \ cpu_machdep.9 cpu_set_upcall.9 \ cpu_machdep.9 cpu_set_user_tls.9 \ cpu_machdep.9 cpu_switch.9 \ cpu_machdep.9 cpu_sync_core.9 \ cpu_machdep.9 cpu_thread_alloc.9 \ cpu_machdep.9 cpu_thread_clean.9 \ cpu_machdep.9 cpu_thread_exit.9 \ cpu_machdep.9 cpu_thread_free.9 \ cpu_machdep.9 cpu_throw.9 \ cpu_machdep.9 cpu_update_pcb.9 MLINKS+=cpuset.9 CPUSET_T_INITIALIZER.9 \ cpuset.9 CPUSET_FSET.9 \ cpuset.9 CPU_CLR.9 \ cpuset.9 CPU_COPY.9 \ cpuset.9 CPU_ISSET.9 \ cpuset.9 CPU_SET.9 \ cpuset.9 CPU_ZERO.9 \ cpuset.9 CPU_FILL.9 \ cpuset.9 CPU_SETOF.9 \ cpuset.9 CPU_EMPTY.9 \ cpuset.9 CPU_ISFULLSET.9 \ cpuset.9 CPU_FFS.9 \ cpuset.9 CPU_COUNT.9 \ cpuset.9 CPU_SUBSET.9 \ cpuset.9 CPU_OVERLAP.9 \ cpuset.9 CPU_CMP.9 \ cpuset.9 CPU_OR.9 \ cpuset.9 CPU_ORNOT.9 \ cpuset.9 CPU_AND.9 \ cpuset.9 CPU_ANDNOT.9 \ cpuset.9 CPU_CLR_ATOMIC.9 \ cpuset.9 CPU_SET_ATOMIC.9 \ cpuset.9 CPU_SET_ATOMIC_ACQ.9 \ cpuset.9 CPU_AND_ATOMIC.9 \ cpuset.9 CPU_OR_ATOMIC.9 \ cpuset.9 CPU_COPY_STORE_REL.9 MLINKS+=critical_enter.9 critical.9 \ critical_enter.9 critical_exit.9 \ critical_enter.9 CRITICAL_ASSERT.9 MLINKS+=crypto_buffer.9 crypto_apply.9 \ crypto_buffer.9 crypto_apply_buf.9 \ crypto_buffer.9 crypto_buffer_contiguous_segment.9 \ crypto_buffer.9 crypto_buffer_len.9 \ crypto_buffer.9 crypto_contiguous_segment.9 \ crypto_buffer.9 crypto_cursor_init.9 \ crypto_buffer.9 crypto_cursor_advance.9 \ crypto_buffer.9 crypto_cursor_copyback.9 \ crypto_buffer.9 crypto_cursor_copydata.9 \ crypto_buffer.9 crypto_cursor_copydata_noadv.9 \ crypto_buffer.9 crypto_cursor_segment.9 \ crypto_buffer.9 CRYPTO_HAS_OUTPUT_BUFFER.9 MLINKS+=crypto_driver.9 crypto_copyback.9 \ crypto_driver.9 crypto_copydata.9 \ crypto_driver.9 crypto_done.9 \ crypto_driver.9 crypto_get_driverid.9 \ crypto_driver.9 crypto_get_driver_session.9 \ crypto_driver.9 crypto_read_iv.9 \ crypto_driver.9 crypto_unblock.9 \ crypto_driver.9 crypto_unregister_all.9 \ crypto_driver.9 CRYPTODEV_FREESESSION.9 \ crypto_driver.9 CRYPTODEV_NEWSESSION.9 \ crypto_driver.9 CRYPTODEV_PROBESESSION.9 \ crypto_driver.9 CRYPTODEV_PROCESS.9 \ crypto_driver.9 hmac_init_ipad.9 \ crypto_driver.9 hmac_init_opad.9 MLINKS+=crypto_request.9 crypto_clonereq.9 \ crypto_request.9 crypto_destroyreq.9 \ crypto_request.9 crypto_dispatch.9 \ crypto_request.9 crypto_freereq.9 \ crypto_request.9 crypto_getreq.9 \ crypto_request.9 crypto_initreq.9 \ crypto_request.9 crypto_use_buf.9 \ crypto_request.9 crypto_use_mbuf.9 \ crypto_request.9 crypto_use_output_buf.9 \ crypto_request.9 crypto_use_output_mbuf.9 \ crypto_request.9 crypto_use_output_uio.9 \ crypto_request.9 crypto_use_uio.9 MLINKS+=crypto_session.9 crypto_auth_hash.9 \ crypto_session.9 crypto_cipher.9 \ crypto_session.9 crypto_get_params.9 \ crypto_session.9 crypto_newsession.9 \ crypto_session.9 crypto_freesession.9 MLINKS+=DB_COMMAND.9 DB_ALIAS.9 \ DB_COMMAND.9 DB_ALIAS_FLAGS.9 \ DB_COMMAND.9 DB_COMMAND_FLAGS.9 \ DB_COMMAND.9 DB_SHOW_ALIAS.9 \ DB_COMMAND.9 DB_SHOW_ALIAS_FLAGS.9 \ DB_COMMAND.9 DB_SHOW_ALL_ALIAS.9 \ DB_COMMAND.9 DB_SHOW_ALL_COMMAND.9 \ DB_COMMAND.9 DB_SHOW_COMMAND.9 \ DB_COMMAND.9 DB_SHOW_COMMAND_FLAGS.9 \ DB_COMMAND.9 DB_DECLARE_TABLE.9 \ DB_COMMAND.9 DB_DEFINE_TABLE.9 \ DB_COMMAND.9 DB_TABLE_COMMAND.9 \ DB_COMMAND.9 DB_TABLE_COMMAND_FLAGS.9 \ DB_COMMAND.9 DB_TABLE_ALIAS.9 \ DB_COMMAND.9 DB_TABLE_ALIAS_FLAGS.9 MLINKS+=DECLARE_MODULE.9 DECLARE_MODULE_TIED.9 MLINKS+=dev_clone.9 drain_dev_clone_events.9 MLINKS+=dev_refthread.9 devvn_refthread.9 \ dev_refthread.9 dev_relthread.9 MLINKS+=devfs_set_cdevpriv.9 devfs_clear_cdevpriv.9 \ devfs_set_cdevpriv.9 devfs_get_cdevpriv.9 \ devfs_set_cdevpriv.9 devfs_foreach_cdevpriv.9 MLINKS+=device_add_child.9 device_add_child_ordered.9 MLINKS+=device_enable.9 device_disable.9 \ device_enable.9 device_is_enabled.9 MLINKS+=device_get_ivars.9 device_set_ivars.9 MLINKS+=device_get_name.9 device_get_nameunit.9 MLINKS+=device_get_state.9 device_busy.9 \ device_get_state.9 device_is_alive.9 \ device_get_state.9 device_is_attached.9 \ device_get_state.9 device_unbusy.9 MLINKS+=device_get_sysctl.9 device_get_sysctl_ctx.9 \ device_get_sysctl.9 device_get_sysctl_tree.9 MLINKS+=device_quiet.9 device_is_quiet.9 \ device_quiet.9 device_verbose.9 MLINKS+=device_set_desc.9 device_get_desc.9 \ device_set_desc.9 device_set_descf.9 \ device_set_desc.9 device_set_desc_copy.9 MLINKS+=device_set_flags.9 device_get_flags.9 MLINKS+=device_probe_and_attach.9 device_attach.9 \ device_probe_and_attach.9 device_detach.9 \ device_probe_and_attach.9 device_probe.9 MLINKS+=devstat.9 devicestat.9 \ devstat.9 devstat_new_entry.9 \ devstat.9 devstat_end_transaction.9 \ devstat.9 devstat_end_transaction_bio.9 \ devstat.9 devstat_remove_entry.9 \ devstat.9 devstat_start_transaction.9 \ devstat.9 devstat_start_transaction_bio.9 MLINKS+=disk.9 disk_add_alias.9 \ disk.9 disk_alloc.9 \ disk.9 disk_create.9 \ disk.9 disk_destroy.9 \ disk.9 disk_gone.9 \ disk.9 disk_resize.9 MLINKS+=dnv.9 dnvlist.9 \ dnv.9 dnvlist_get_binary.9 \ dnv.9 dnvlist_get_bool.9 \ dnv.9 dnvlist_get_descriptor.9 \ dnv.9 dnvlist_get_number.9 \ dnv.9 dnvlist_get_nvlist.9 \ dnv.9 dnvlist_get_string.9 \ dnv.9 dnvlist_take_binary.9 \ dnv.9 dnvlist_take_bool.9 \ dnv.9 dnvlist_take_descriptor.9 \ dnv.9 dnvlist_take_number.9 \ dnv.9 dnvlist_take_nvlist.9 \ dnv.9 dnvlist_take_string.9 MLINKS+=domain.9 protosw.9 \ domain.9 domain_add.9 \ domain.9 protosw_register.9 \ domain.9 protosw_unregister.9 MLINKS+=dpcpu.9 DPCPU_DECLARE.9 \ dpcpu.9 DPCPU_DEFINE.9 \ dpcpu.9 DPCPU_DEFINE_STATIC.9 \ dpcpu.9 DPCPU_GET.9 \ dpcpu.9 DPCPU_ID_PTR.9 \ dpcpu.9 DPCPU_ID_GET.9 \ dpcpu.9 DPCPU_ID_SET.9 \ dpcpu.9 DPCPU_PTR.9 \ dpcpu.9 DPCPU_SET.9 MLINKS+=drbr.9 drbr_free.9 \ drbr.9 drbr_enqueue.9 \ drbr.9 drbr_dequeue.9 \ drbr.9 drbr_dequeue_cond.9 \ drbr.9 drbr_flush.9 \ drbr.9 drbr_empty.9 \ drbr.9 drbr_inuse.9 \ drbr.9 drbr_stats_update.9 MLINKS+=DRIVER_MODULE.9 DRIVER_MODULE_ORDERED.9 \ DRIVER_MODULE.9 EARLY_DRIVER_MODULE.9 \ DRIVER_MODULE.9 EARLY_DRIVER_MODULE_ORDERED.9 MLINKS+=epoch.9 epoch_context.9 \ epoch.9 epoch_alloc.9 \ epoch.9 epoch_free.9 \ epoch.9 epoch_enter.9 \ epoch.9 epoch_exit.9 \ epoch.9 epoch_wait.9 \ epoch.9 epoch_call.9 \ epoch.9 epoch_drain_callbacks.9 \ epoch.9 in_epoch.9 MLINKS+=EVENTHANDLER.9 EVENTHANDLER_DECLARE.9 \ EVENTHANDLER.9 EVENTHANDLER_DEFINE.9 \ EVENTHANDLER.9 EVENTHANDLER_DEREGISTER.9 \ EVENTHANDLER.9 eventhandler_deregister.9 \ EVENTHANDLER.9 eventhandler_find_list.9 \ EVENTHANDLER.9 EVENTHANDLER_INVOKE.9 \ EVENTHANDLER.9 eventhandler_prune_list.9 \ EVENTHANDLER.9 EVENTHANDLER_REGISTER.9 \ EVENTHANDLER.9 eventhandler_register.9 MLINKS+=eventtimers.9 et_register.9 \ eventtimers.9 et_deregister.9 \ eventtimers.9 et_ban.9 \ eventtimers.9 et_find.9 \ eventtimers.9 et_free.9 \ eventtimers.9 et_init.9 \ eventtimers.9 ET_LOCK.9 \ eventtimers.9 ET_UNLOCK.9 \ eventtimers.9 et_start.9 \ eventtimers.9 et_stop.9 MLINKS+=fail.9 KFAIL_POINT_CODE.9 \ fail.9 KFAIL_POINT_ERROR.9 \ fail.9 KFAIL_POINT_GOTO.9 \ fail.9 KFAIL_POINT_RETURN.9 \ fail.9 KFAIL_POINT_RETURN_VOID.9 MLINKS+=fdt_pinctrl.9 fdt_pinctrl_configure.9 \ fdt_pinctrl.9 fdt_pinctrl_configure_by_name.9 \ fdt_pinctrl.9 fdt_pinctrl_configure_tree.9 \ fdt_pinctrl.9 fdt_pinctrl_register.9 MLINKS+=fetch.9 fubyte.9 \ fetch.9 fuword.9 \ fetch.9 fuword16.9 \ fetch.9 fuword32.9 \ fetch.9 fuword64.9 \ fetch.9 fueword.9 \ fetch.9 fueword32.9 \ fetch.9 fueword64.9 MLINKS+=firmware.9 firmware_get.9 \ firmware.9 firmware_put.9 \ firmware.9 firmware_register.9 \ firmware.9 firmware_unregister.9 MLINKS+=fpu_kern.9 fpu_kern_alloc_ctx.9 \ fpu_kern.9 fpu_kern_free_ctx.9 \ fpu_kern.9 fpu_kern_enter.9 \ fpu_kern.9 fpu_kern_leave.9 \ fpu_kern.9 fpu_kern_thread.9 \ fpu_kern.9 is_fpu_kern_thread.9 MLINKS+=g_attach.9 g_detach.9 MLINKS+=g_bio.9 bio.9 \ g_bio.9 g_alloc_bio.9 \ g_bio.9 g_clone_bio.9 \ g_bio.9 g_destroy_bio.9 \ g_bio.9 g_duplicate_bio.9 \ g_bio.9 g_format_bio.9 \ g_bio.9 g_new_bio.9 \ g_bio.9 g_print_bio.9 \ g_bio.9 g_reset_bio.9 MLINKS+=g_consumer.9 g_destroy_consumer.9 \ g_consumer.9 g_new_consumer.9 MLINKS+=g_data.9 g_read_data.9 \ g_data.9 g_write_data.9 MLINKS+=getenv.9 freeenv.9 \ getenv.9 getenv_int.9 \ getenv.9 getenv_long.9 \ getenv.9 getenv_string.9 \ getenv.9 getenv_quad.9 \ getenv.9 getenv_uint.9 \ getenv.9 getenv_ulong.9 \ getenv.9 getenv_bool.9 \ getenv.9 getenv_is_true.9 \ getenv.9 getenv_is_false.9 \ getenv.9 kern_getenv.9 \ getenv.9 kern_setenv.9 \ getenv.9 kern_unsetenv.9 \ getenv.9 setenv.9 \ getenv.9 testenv.9 \ getenv.9 unsetenv.9 MLINKS+=g_event.9 g_cancel_event.9 \ g_event.9 g_post_event.9 \ g_event.9 g_waitfor_event.9 MLINKS+=g_geom.9 g_destroy_geom.9 \ g_geom.9 g_new_geomf.9 MLINKS+=g_provider.9 g_destroy_provider.9 \ g_provider.9 g_error_provider.9 \ g_provider.9 g_new_providerf.9 MLINKS+=gone_in.9 gone_in_dev.9 MLINKS+=groupmember.9 realgroupmember.9 MLINKS+=hash.9 hash32.9 \ hash.9 hash32_buf.9 \ hash.9 hash32_str.9 \ hash.9 hash32_stre.9 \ hash.9 hash32_strn.9 \ hash.9 hash32_strne.9 \ hash.9 jenkins_hash.9 \ hash.9 jenkins_hash32.9 MLINKS+=hashinit.9 hashdestroy.9 \ hashinit.9 hashinit_flags.9 \ hashinit.9 phashinit.9 MLINKS+=hhook.9 hhook_head_register.9 \ hhook.9 hhook_head_deregister.9 \ hhook.9 hhook_head_deregister_lookup.9 \ hhook.9 hhook_run_hooks.9 \ hhook.9 HHOOKS_RUN_IF.9 \ hhook.9 HHOOKS_RUN_LOOKUP_IF.9 MLINKS+=hz.9 tick.9 MLINKS+=ieee80211.9 ieee80211_ifattach.9 \ ieee80211.9 ieee80211_ifdetach.9 MLINKS+=ieee80211_amrr.9 ieee80211_amrr_choose.9 \ ieee80211_amrr.9 ieee80211_amrr_cleanup.9 \ ieee80211_amrr.9 ieee80211_amrr_init.9 \ ieee80211_amrr.9 ieee80211_amrr_node_init.9 \ ieee80211_amrr.9 ieee80211_amrr_setinterval.9 \ ieee80211_amrr.9 ieee80211_amrr_tx_complete.9 \ ieee80211_amrr.9 ieee80211_amrr_tx_update.9 MLINKS+=ieee80211_beacon.9 ieee80211_beacon_alloc.9 \ ieee80211_beacon.9 ieee80211_beacon_notify.9 \ ieee80211_beacon.9 ieee80211_beacon_update.9 MLINKS+=ieee80211_bmiss.9 ieee80211_beacon_miss.9 MLINKS+=ieee80211_crypto.9 ieee80211_crypto_available.9 \ ieee80211_crypto.9 ieee80211_crypto_decap.9 \ ieee80211_crypto.9 ieee80211_crypto_delglobalkeys.9 \ ieee80211_crypto.9 ieee80211_crypto_delkey.9 \ ieee80211_crypto.9 ieee80211_crypto_demic.9 \ ieee80211_crypto.9 ieee80211_crypto_encap.9 \ ieee80211_crypto.9 ieee80211_crypto_enmic.9 \ ieee80211_crypto.9 ieee80211_crypto_newkey.9 \ ieee80211_crypto.9 ieee80211_crypto_register.9 \ ieee80211_crypto.9 ieee80211_crypto_reload_keys.9 \ ieee80211_crypto.9 ieee80211_crypto_setkey.9 \ ieee80211_crypto.9 ieee80211_crypto_unregister.9 \ ieee80211_crypto.9 ieee80211_key_update_begin.9 \ ieee80211_crypto.9 ieee80211_key_update_end.9 \ ieee80211_crypto.9 ieee80211_notify_michael_failure.9 \ ieee80211_crypto.9 ieee80211_notify_replay_failure.9 MLINKS+=ieee80211_input.9 ieee80211_input_all.9 MLINKS+=ieee80211_node.9 ieee80211_dump_node.9 \ ieee80211_node.9 ieee80211_dump_nodes.9 \ ieee80211_node.9 ieee80211_find_rxnode.9 \ ieee80211_node.9 ieee80211_find_rxnode_withkey.9 \ ieee80211_node.9 ieee80211_free_node.9 \ ieee80211_node.9 ieee80211_iterate_nodes.9 \ ieee80211_node.9 ieee80211_ref_node.9 MLINKS+=ieee80211_output.9 ieee80211_process_callback.9 \ ieee80211_output.9 M_SEQNO_GET.9 \ ieee80211_output.9 M_WME_GETAC.9 MLINKS+=ieee80211_proto.9 ieee80211_new_state.9 \ ieee80211_proto.9 ieee80211_resume_all.9 \ ieee80211_proto.9 ieee80211_start_all.9 \ ieee80211_proto.9 ieee80211_stop_all.9 \ ieee80211_proto.9 ieee80211_suspend_all.9 \ ieee80211_proto.9 ieee80211_waitfor_parent.9 MLINKS+=ieee80211_radiotap.9 ieee80211_radiotap_active.9 \ ieee80211_radiotap.9 ieee80211_radiotap_active_vap.9 \ ieee80211_radiotap.9 ieee80211_radiotap_attach.9 \ ieee80211_radiotap.9 ieee80211_radiotap_tx.9 \ ieee80211_radiotap.9 radiotap.9 MLINKS+=ieee80211_regdomain.9 ieee80211_alloc_countryie.9 \ ieee80211_regdomain.9 ieee80211_init_channels.9 \ ieee80211_regdomain.9 ieee80211_sort_channels.9 MLINKS+=ieee80211_scan.9 ieee80211_add_scan.9 \ ieee80211_scan.9 ieee80211_bg_scan.9 \ ieee80211_scan.9 ieee80211_cancel_scan.9 \ ieee80211_scan.9 ieee80211_cancel_scan_any.9 \ ieee80211_scan.9 ieee80211_check_scan.9 \ ieee80211_scan.9 ieee80211_check_scan_current.9 \ ieee80211_scan.9 ieee80211_flush.9 \ ieee80211_scan.9 ieee80211_probe_curchan.9 \ ieee80211_scan.9 ieee80211_scan_assoc_fail.9 \ ieee80211_scan.9 ieee80211_scan_done.9 \ ieee80211_scan.9 ieee80211_scan_dump_channels.9 \ ieee80211_scan.9 ieee80211_scan_flush.9 \ ieee80211_scan.9 ieee80211_scan_iterate.9 \ ieee80211_scan.9 ieee80211_scan_next.9 \ ieee80211_scan.9 ieee80211_scan_timeout.9 \ ieee80211_scan.9 ieee80211_scanner_get.9 \ ieee80211_scan.9 ieee80211_scanner_register.9 \ ieee80211_scan.9 ieee80211_scanner_unregister.9 \ ieee80211_scan.9 ieee80211_scanner_unregister_all.9 \ ieee80211_scan.9 ieee80211_start_scan.9 MLINKS+=ieee80211_vap.9 ieee80211_vap_attach.9 \ ieee80211_vap.9 ieee80211_vap_detach.9 \ ieee80211_vap.9 ieee80211_vap_setup.9 MLINKS+=iflibdd.9 ifdi_attach_pre.9 \ iflibdd.9 ifdi_attach_post.9 \ iflibdd.9 ifdi_detach.9 \ iflibdd.9 ifdi_get_counter.9 \ iflibdd.9 ifdi_i2c_req.9 \ iflibdd.9 ifdi_init.9 \ iflibdd.9 ifdi_intr_enable.9 \ iflibdd.9 ifdi_intr_disable.9 \ iflibdd.9 ifdi_led_func.9 \ iflibdd.9 ifdi_link_intr_enable.9 \ iflibdd.9 ifdi_media_set.9 \ iflibdd.9 ifdi_media_status.9 \ iflibdd.9 ifdi_media_change.9 \ iflibdd.9 ifdi_mtu_set.9 \ iflibdd.9 ifdi_multi_set.9 \ iflibdd.9 ifdi_promisc_set.9 \ iflibdd.9 ifdi_queues_alloc.9 \ iflibdd.9 ifdi_queues_free.9 \ iflibdd.9 ifdi_queue_intr_enable.9 \ iflibdd.9 ifdi_resume.9 \ iflibdd.9 ifdi_rxq_setup.9 \ iflibdd.9 ifdi_stop.9 \ iflibdd.9 ifdi_suspend.9 \ iflibdd.9 ifdi_sysctl_int_delay.9 \ iflibdd.9 ifdi_timer.9 \ iflibdd.9 ifdi_txq_setup.9 \ iflibdd.9 ifdi_update_admin_status.9 \ iflibdd.9 ifdi_vf_add.9 \ iflibdd.9 ifdi_vflr_handle.9 \ iflibdd.9 ifdi_vlan_register.9 \ iflibdd.9 ifdi_vlan_unregister.9 \ iflibdd.9 ifdi_watchdog_reset.9 \ iflibdd.9 iov_init.9 \ iflibdd.9 iov_uinit.9 MLINKS+=iflibdi.9 iflib_add_int_delay_sysctl.9 \ iflibdi.9 iflib_device_attach.9 \ iflibdi.9 iflib_device_deregister.9 \ iflibdi.9 iflib_device_detach.9 \ iflibdi.9 iflib_device_suspend.9 \ iflibdi.9 iflib_device_register.9 \ iflibdi.9 iflib_device_resume.9 \ iflibdi.9 iflib_led_create.9 \ iflibdi.9 iflib_irq_alloc.9 \ iflibdi.9 iflib_irq_alloc_generic.9 \ iflibdi.9 iflib_link_intr_deferred.9 \ iflibdi.9 iflib_link_state_change.9 \ iflibdi.9 iflib_rx_intr_deferred.9 \ iflibdi.9 iflib_tx_intr_deferred.9 MLINKS+=iflibtxrx.9 isc_rxd_available.9 \ iflibtxrx.9 isc_rxd_refill.9 \ iflibtxrx.9 isc_rxd_flush.9 \ iflibtxrx.9 isc_rxd_pkt_get.9 \ iflibtxrx.9 isc_txd_credits_update.9 \ iflibtxrx.9 isc_txd_encap.9 \ iflibtxrx.9 isc_txd_flush.9 MLINKS+=ifnet.9 if_addmulti.9 \ ifnet.9 if_alloc.9 \ ifnet.9 if_alloc_dev.9 \ ifnet.9 if_alloc_domain.9 \ ifnet.9 if_allmulti.9 \ ifnet.9 if_attach.9 \ ifnet.9 if_data.9 \ ifnet.9 IF_DEQUEUE.9 \ ifnet.9 if_delmulti.9 \ ifnet.9 if_detach.9 \ ifnet.9 if_down.9 \ ifnet.9 if_findmulti.9 \ ifnet.9 if_free.9 \ ifnet.9 if_free_type.9 \ ifnet.9 if_up.9 \ ifnet.9 ifa_free.9 \ ifnet.9 ifa_ifwithaddr.9 \ ifnet.9 ifa_ifwithdstaddr.9 \ ifnet.9 ifa_ifwithnet.9 \ ifnet.9 ifa_ref.9 \ ifnet.9 ifaddr.9 \ ifnet.9 ifaof_ifpforaddr.9 \ ifnet.9 ifioctl.9 \ ifnet.9 ifpromisc.9 \ ifnet.9 ifqueue.9 \ ifnet.9 ifunit.9 \ ifnet.9 ifunit_ref.9 # IfAPI MLINKS+=ifnet.9 ifapi.9 MLINKS+=insmntque.9 insmntque1.9 MLINKS+=intr_event.9 intr_event_add_handler.9 \ intr_event.9 intr_event_create.9 \ intr_event.9 intr_event_destroy.9 \ intr_event.9 intr_event_handle.9 \ intr_event.9 intr_event_remove_handler.9 \ intr_event.9 intr_priority.9 MLINKS+=KASSERT.9 MPASS.9 MLINKS+=kern_reboot.9 reboot.9 \ kern_reboot.9 shutdown_nice.9 MLINKS+=kern_yield.9 maybe_yield.9 \ kern_yield.9 should_yield.9 MLINKS+=kernacc.9 useracc.9 MLINKS+=kernel_mount.9 free_mntarg.9 \ kernel_mount.9 mount_arg.9 \ kernel_mount.9 mount_argb.9 \ kernel_mount.9 mount_argf.9 \ kernel_mount.9 mount_argsu.9 MLINKS+=kasan.9 KASAN.9 \ kasan.9 kasan_mark.9 MLINKS+=khelp.9 khelp_add_hhook.9 \ khelp.9 KHELP_DECLARE_MOD.9 \ khelp.9 KHELP_DECLARE_MOD_UMA.9 \ khelp.9 khelp_destroy_osd.9 \ khelp.9 khelp_get_id.9 \ khelp.9 khelp_get_osd.9 \ khelp.9 khelp_init_osd.9 \ khelp.9 khelp_remove_hhook.9 MLINKS+=kmsan.9 KMSAN.9 \ kmsan.9 kmsan_check.9 \ kmsan.9 kmsan_check_bio.9 \ kmsan.9 kmsan_check_ccb.9 \ kmsan.9 kmsan_check_mbuf.9 \ kmsan.9 kmsan_check_uio.9 \ kmsan.9 kmsan_mark.9 \ kmsan.9 kmsan_oirg.9 MLINKS+=kobj.9 DEFINE_CLASS.9 \ kobj.9 kobj_class_compile.9 \ kobj.9 kobj_class_compile_static.9 \ kobj.9 kobj_class_free.9 \ kobj.9 kobj_create.9 \ kobj.9 kobj_delete.9 \ kobj.9 kobj_init.9 \ kobj.9 kobj_init_static.9 MLINKS+=kproc.9 kproc_create.9 \ kproc.9 kproc_exit.9 \ kproc.9 kproc_kthread_add.9 \ kproc.9 kproc_resume.9 \ kproc.9 kproc_shutdown.9 \ kproc.9 kproc_start.9 \ kproc.9 kproc_suspend.9 \ kproc.9 kproc_suspend_check.9 \ kproc.9 kthread_create.9 MLINKS+=kqueue.9 knlist_add.9 \ kqueue.9 knlist_clear.9 \ kqueue.9 knlist_delete.9 \ kqueue.9 knlist_destroy.9 \ kqueue.9 knlist_empty.9 \ kqueue.9 knlist_init.9 \ kqueue.9 knlist_init_mtx.9 \ kqueue.9 knlist_remove.9 \ kqueue.9 knote_fdclose.9 \ kqueue.9 KNOTE_LOCKED.9 \ kqueue.9 KNOTE_UNLOCKED.9 \ kqueue.9 kqfd_register.9 \ kqueue.9 kqueue_add_filteropts.9 \ kqueue.9 kqueue_del_filteropts.9 MLINKS+=kthread.9 kthread_add.9 \ kthread.9 kthread_exit.9 \ kthread.9 kthread_resume.9 \ kthread.9 kthread_shutdown.9 \ kthread.9 kthread_start.9 \ kthread.9 kthread_suspend.9 \ kthread.9 kthread_suspend_check.9 MLINKS+=ktr.9 CTR0.9 \ ktr.9 CTR1.9 \ ktr.9 CTR2.9 \ ktr.9 CTR3.9 \ ktr.9 CTR4.9 \ ktr.9 CTR5.9 \ ktr.9 CTR6.9 MLINKS+=lock.9 lockdestroy.9 \ lock.9 lockinit.9 \ lock.9 lockmgr.9 \ lock.9 lockmgr_args.9 \ lock.9 lockmgr_args_rw.9 \ lock.9 lockmgr_assert.9 \ lock.9 lockmgr_disown.9 \ lock.9 lockmgr_disowned.9 \ lock.9 lockmgr_lock_flags.9 \ lock.9 lockmgr_printinfo.9 \ lock.9 lockmgr_recursed.9 \ lock.9 lockmgr_rw.9 \ lock.9 lockmgr_slock.9 \ lock.9 lockmgr_unlock.9 \ lock.9 lockmgr_xlock.9 \ lock.9 lockstatus.9 MLINKS+=LOCK_PROFILING.9 MUTEX_PROFILING.9 MLINKS+=make_dev.9 destroy_dev.9 \ make_dev.9 destroy_dev_drain.9 \ make_dev.9 destroy_dev_sched.9 \ make_dev.9 destroy_dev_sched_cb.9 \ make_dev.9 dev_depends.9 \ make_dev.9 make_dev_alias.9 \ make_dev.9 make_dev_alias_p.9 \ make_dev.9 make_dev_cred.9 \ make_dev.9 make_dev_credf.9 \ make_dev.9 make_dev_p.9 \ make_dev.9 make_dev_s.9 MLINKS+=malloc.9 free.9 \ malloc.9 malloc_aligned.9 \ malloc.9 malloc_domainset.9 \ malloc.9 malloc_domainset_aligned.9 \ malloc.9 malloc_domainset_exec.9 \ malloc.9 malloc_exec.9 \ malloc.9 malloc_usable_size.9 \ malloc.9 mallocarray.9 \ malloc.9 mallocarray_domainset.9 \ malloc.9 MALLOC_DECLARE.9 \ malloc.9 MALLOC_DEFINE.9 \ malloc.9 realloc.9 \ malloc.9 reallocf.9 \ malloc.9 zfree.9 MLINKS+=mbchain.9 mb_detach.9 \ mbchain.9 mb_done.9 \ mbchain.9 mb_fixhdr.9 \ mbchain.9 mb_init.9 \ mbchain.9 mb_initm.9 \ mbchain.9 mb_put_int64be.9 \ mbchain.9 mb_put_int64le.9 \ mbchain.9 mb_put_mbuf.9 \ mbchain.9 mb_put_mem.9 \ mbchain.9 mb_put_uint16be.9 \ mbchain.9 mb_put_uint16le.9 \ mbchain.9 mb_put_uint32be.9 \ mbchain.9 mb_put_uint32le.9 \ mbchain.9 mb_put_uint8.9 \ mbchain.9 mb_put_uio.9 \ mbchain.9 mb_reserve.9 MLINKS+=\ mbuf.9 m_adj.9 \ mbuf.9 m_align.9 \ mbuf.9 M_ALIGN.9 \ mbuf.9 m_append.9 \ mbuf.9 m_apply.9 \ mbuf.9 m_cat.9 \ mbuf.9 m_catpkt.9 \ mbuf.9 MCHTYPE.9 \ mbuf.9 MCLGET.9 \ mbuf.9 m_collapse.9 \ mbuf.9 m_copyback.9 \ mbuf.9 m_copydata.9 \ mbuf.9 m_copym.9 \ mbuf.9 m_copypacket.9 \ mbuf.9 m_copyup.9 \ mbuf.9 m_defrag.9 \ mbuf.9 m_devget.9 \ mbuf.9 m_dup.9 \ mbuf.9 m_dup_pkthdr.9 \ mbuf.9 MEXTADD.9 \ mbuf.9 m_fixhdr.9 \ mbuf.9 m_free.9 \ mbuf.9 m_freem.9 \ mbuf.9 MGET.9 \ mbuf.9 m_get.9 \ mbuf.9 m_get2.9 \ mbuf.9 m_get3.9 \ mbuf.9 m_getjcl.9 \ mbuf.9 m_getcl.9 \ mbuf.9 MGETHDR.9 \ mbuf.9 m_gethdr.9 \ mbuf.9 m_getm.9 \ mbuf.9 m_getptr.9 \ mbuf.9 MH_ALIGN.9 \ mbuf.9 M_LEADINGSPACE.9 \ mbuf.9 m_length.9 \ mbuf.9 M_MOVE_PKTHDR.9 \ mbuf.9 m_move_pkthdr.9 \ mbuf.9 M_PREPEND.9 \ mbuf.9 m_prepend.9 \ mbuf.9 m_pulldown.9 \ mbuf.9 m_pullup.9 \ mbuf.9 m_split.9 \ mbuf.9 mtod.9 \ mbuf.9 mtodo.9 \ mbuf.9 M_TRAILINGSPACE.9 \ mbuf.9 m_unshare.9 \ mbuf.9 M_WRITABLE.9 MLINKS+=\ mbuf_tags.9 m_tag_alloc.9 \ mbuf_tags.9 m_tag_copy.9 \ mbuf_tags.9 m_tag_copy_chain.9 \ mbuf_tags.9 m_tag_delete.9 \ mbuf_tags.9 m_tag_delete_chain.9 \ mbuf_tags.9 m_tag_delete_nonpersistent.9 \ mbuf_tags.9 m_tag_find.9 \ mbuf_tags.9 m_tag_first.9 \ mbuf_tags.9 m_tag_free.9 \ mbuf_tags.9 m_tag_get.9 \ mbuf_tags.9 m_tag_init.9 \ mbuf_tags.9 m_tag_locate.9 \ mbuf_tags.9 m_tag_next.9 \ mbuf_tags.9 m_tag_prepend.9 \ mbuf_tags.9 m_tag_unlink.9 MLINKS+=mdchain.9 md_append_record.9 \ mdchain.9 md_done.9 \ mdchain.9 md_get_int64.9 \ mdchain.9 md_get_int64be.9 \ mdchain.9 md_get_int64le.9 \ mdchain.9 md_get_mbuf.9 \ mdchain.9 md_get_mem.9 \ mdchain.9 md_get_uint16.9 \ mdchain.9 md_get_uint16be.9 \ mdchain.9 md_get_uint16le.9 \ mdchain.9 md_get_uint32.9 \ mdchain.9 md_get_uint32be.9 \ mdchain.9 md_get_uint32le.9 \ mdchain.9 md_get_uint8.9 \ mdchain.9 md_get_uio.9 \ mdchain.9 md_initm.9 \ mdchain.9 md_next_record.9 MLINKS+=microtime.9 bintime.9 \ microtime.9 getbintime.9 \ microtime.9 getmicrotime.9 \ microtime.9 getnanotime.9 \ microtime.9 nanotime.9 MLINKS+=microuptime.9 binuptime.9 \ microuptime.9 getbinuptime.9 \ microuptime.9 getmicrouptime.9 \ microuptime.9 getnanouptime.9 \ microuptime.9 getsbinuptime.9 \ microuptime.9 nanouptime.9 \ microuptime.9 sbinuptime.9 MLINKS+=mod_cc.9 CCV.9 \ mod_cc.9 DECLARE_CC_MODULE.9 MLINKS+=mtx_pool.9 mtx_pool_alloc.9 \ mtx_pool.9 mtx_pool_create.9 \ mtx_pool.9 mtx_pool_destroy.9 \ mtx_pool.9 mtx_pool_find.9 \ mtx_pool.9 mtx_pool_lock.9 \ mtx_pool.9 mtx_pool_lock_spin.9 \ mtx_pool.9 mtx_pool_unlock.9 \ mtx_pool.9 mtx_pool_unlock_spin.9 MLINKS+=mutex.9 mtx_assert.9 \ mutex.9 mtx_destroy.9 \ mutex.9 mtx_init.9 \ mutex.9 mtx_initialized.9 \ mutex.9 mtx_lock.9 \ mutex.9 mtx_lock_flags.9 \ mutex.9 mtx_lock_spin.9 \ mutex.9 mtx_lock_spin_flags.9 \ mutex.9 mtx_owned.9 \ mutex.9 mtx_recursed.9 \ mutex.9 mtx_sleep.9 \ mutex.9 MTX_SYSINIT.9 \ mutex.9 mtx_trylock.9 \ mutex.9 mtx_trylock_flags.9 \ mutex.9 mtx_trylock_spin.9 \ mutex.9 mtx_trylock_spin_flags.9 \ mutex.9 mtx_unlock.9 \ mutex.9 mtx_unlock_flags.9 \ mutex.9 mtx_unlock_spin.9 \ mutex.9 mtx_unlock_spin_flags.9 MLINKS+=namei.9 NDFREE_PNBUF.9 \ namei.9 NDINIT_AT.9 \ namei.9 NDINIT.9 MLINKS+=netisr.9 netisr_clearqdrops.9 \ netisr.9 netisr_default_flow2cpu.9 \ netisr.9 netisr_dispatch.9 \ netisr.9 netisr_dispatch_src.9 \ netisr.9 netisr_get_cpucount.9 \ netisr.9 netisr_get_cpuid.9 \ netisr.9 netisr_getqdrops.9 \ netisr.9 netisr_getqlimit.9 \ netisr.9 netisr_queue.9 \ netisr.9 netisr_queue_src.9 \ netisr.9 netisr_register.9 \ netisr.9 netisr_setqlimit.9 \ netisr.9 netisr_unregister.9 MLINKS+=nv.9 libnv.9 \ nv.9 nvlist.9 \ nv.9 nvlist_add_binary.9 \ nv.9 nvlist_add_bool.9 \ nv.9 nvlist_add_bool_array.9 \ nv.9 nvlist_add_descriptor.9 \ nv.9 nvlist_add_descriptor_array.9 \ nv.9 nvlist_add_null.9 \ nv.9 nvlist_add_number.9 \ nv.9 nvlist_add_number_array.9 \ nv.9 nvlist_add_nvlist.9 \ nv.9 nvlist_add_nvlist_array.9 \ nv.9 nvlist_add_string.9 \ nv.9 nvlist_add_stringf.9 \ nv.9 nvlist_add_stringv.9 \ nv.9 nvlist_add_string_array.9 \ nv.9 nvlist_append_bool_array.9 \ nv.9 nvlist_append_descriptor_array.9 \ nv.9 nvlist_append_nvlist_array.9 \ nv.9 nvlist_append_number_array.9 \ nv.9 nvlist_append_string_array.9 \ nv.9 nvlist_clone.9 \ nv.9 nvlist_create.9 \ nv.9 nvlist_destroy.9 \ nv.9 nvlist_dump.9 \ nv.9 nvlist_empty.9 \ nv.9 nvlist_error.9 \ nv.9 nvlist_exists.9 \ nv.9 nvlist_exists_binary.9 \ nv.9 nvlist_exists_bool.9 \ nv.9 nvlist_exists_bool_array.9 \ nv.9 nvlist_exists_descriptor.9 \ nv.9 nvlist_exists_descriptor_array.9 \ nv.9 nvlist_exists_null.9 \ nv.9 nvlist_exists_number.9 \ nv.9 nvlist_exists_number_array.9 \ nv.9 nvlist_exists_nvlist.9 \ nv.9 nvlist_exists_nvlist_array.9 \ nv.9 nvlist_exists_string.9 \ nv.9 nvlist_exists_type.9 \ nv.9 nvlist_fdump.9 \ nv.9 nvlist_flags.9 \ nv.9 nvlist_free.9 \ nv.9 nvlist_free_binary.9 \ nv.9 nvlist_free_bool.9 \ nv.9 nvlist_free_bool_array.9 \ nv.9 nvlist_free_descriptor.9 \ nv.9 nvlist_free_descriptor_array.9 \ nv.9 nvlist_free_null.9 \ nv.9 nvlist_free_number.9 \ nv.9 nvlist_free_number_array.9 \ nv.9 nvlist_free_nvlist.9 \ nv.9 nvlist_free_nvlist_array.9 \ nv.9 nvlist_free_string.9 \ nv.9 nvlist_free_string_array.9 \ nv.9 nvlist_free_type.9 \ nv.9 nvlist_get_binary.9 \ nv.9 nvlist_get_bool.9 \ nv.9 nvlist_get_bool_array.9 \ nv.9 nvlist_get_descriptor.9 \ nv.9 nvlist_get_descriptor_array.9 \ nv.9 nvlist_get_number.9 \ nv.9 nvlist_get_number_array.9 \ nv.9 nvlist_get_nvlist.9 \ nv.9 nvlist_get_nvlist_array.9 \ nv.9 nvlist_get_parent.9 \ nv.9 nvlist_get_string.9 \ nv.9 nvlist_get_string_array.9 \ nv.9 nvlist_move_binary.9 \ nv.9 nvlist_move_descriptor.9 \ nv.9 nvlist_move_descriptor_array.9 \ nv.9 nvlist_move_nvlist.9 \ nv.9 nvlist_move_nvlist_array.9 \ nv.9 nvlist_move_string.9 \ nv.9 nvlist_move_string_array.9 \ nv.9 nvlist_next.9 \ nv.9 nvlist_pack.9 \ nv.9 nvlist_recv.9 \ nv.9 nvlist_send.9 \ nv.9 nvlist_set_error.9 \ nv.9 nvlist_size.9 \ nv.9 nvlist_take_binary.9 \ nv.9 nvlist_take_bool.9 \ nv.9 nvlist_take_bool_array.9 \ nv.9 nvlist_take_descriptor.9 \ nv.9 nvlist_take_descriptor_array.9 \ nv.9 nvlist_take_number.9 \ nv.9 nvlist_take_number_array.9 \ nv.9 nvlist_take_nvlist.9 \ nv.9 nvlist_take_nvlist_array.9 \ nv.9 nvlist_take_string.9 \ nv.9 nvlist_take_string_array.9 \ nv.9 nvlist_unpack.9 \ nv.9 nvlist_xfer.9 MLINKS+=OF_child.9 OF_parent.9 \ OF_child.9 OF_peer.9 MLINKS+=OF_device_from_xref.9 OF_device_register_xref.9 \ OF_device_from_xref.9 OF_xref_from_device.9 MLINKS+=OF_getprop.9 OF_getencprop.9 \ OF_getprop.9 OF_getencprop_alloc.9 \ OF_getprop.9 OF_getencprop_alloc_multi.9 \ OF_getprop.9 OF_getprop_alloc.9 \ OF_getprop.9 OF_getprop_alloc_multi.9 \ OF_getprop.9 OF_getproplen.9 \ OF_getprop.9 OF_hasprop.9 \ OF_getprop.9 OF_nextprop.9 \ OF_getprop.9 OF_prop_free.9 \ OF_getprop.9 OF_searchencprop.9 \ OF_getprop.9 OF_searchprop.9 \ OF_getprop.9 OF_setprop.9 MLINKS+=OF_node_from_xref.9 OF_xref_from_node.9 MLINKS+=ofw_bus_is_compatible.9 ofw_bus_is_compatible_strict.9 \ ofw_bus_is_compatible.9 ofw_bus_node_is_compatible.9 \ ofw_bus_is_compatible.9 ofw_bus_search_compatible.9 MLINKS+= ofw_bus_status_okay.9 ofw_bus_get_status.9 \ ofw_bus_status_okay.9 ofw_bus_node_status_okay.9 MLINKS+=ofw_graph.9 ofw_graph_get_device_by_port_ep.9 \ ofw_graph.9 ofw_graph_get_endpoint_by_idx.9 \ ofw_graph.9 ofw_graph_get_port_by_idx.9 \ ofw_graph.9 ofw_graph_get_remove_endpoint.9 \ ofw_graph.9 ofw_graph_get_remove_parent.9 \ ofw_graph.9 ofw_graph_port_get_num_endpoints.9 MLINKS+=osd.9 osd_call.9 \ osd.9 osd_del.9 \ osd.9 osd_deregister.9 \ osd.9 osd_exit.9 \ osd.9 osd_free_reserved.9 \ osd.9 osd_get.9 \ osd.9 osd_register.9 \ osd.9 osd_reserve.9 \ osd.9 osd_set.9 \ osd.9 osd_set_reserved.9 MLINKS+=panic.9 vpanic.9 \ panic.9 KERNEL_PANICKED.9 MLINKS+=pci.9 pci_alloc_msi.9 \ pci.9 pci_alloc_msix.9 \ pci.9 pci_clear_pme.9 \ pci.9 pci_disable_busmaster.9 \ pci.9 pci_disable_io.9 \ pci.9 pci_enable_busmaster.9 \ pci.9 pci_enable_io.9 \ pci.9 pci_enable_pme.9 \ pci.9 pci_find_bsf.9 \ pci.9 pci_find_cap.9 \ pci.9 pci_find_dbsf.9 \ pci.9 pci_find_device.9 \ pci.9 pci_find_extcap.9 \ pci.9 pci_find_htcap.9 \ pci.9 pci_find_pcie_root_port.9 \ pci.9 pci_get_id.9 \ pci.9 pci_get_max_read_req.9 \ pci.9 pci_get_powerstate.9 \ pci.9 pci_get_vpd_ident.9 \ pci.9 pci_get_vpd_readonly.9 \ pci.9 pci_has_pm.9 \ pci.9 pci_iov_attach.9 \ pci.9 pci_iov_attach_name.9 \ pci.9 pci_iov_detach.9 \ pci.9 pci_msi_count.9 \ pci.9 pci_msix_count.9 \ pci.9 pci_msix_pba_bar.9 \ pci.9 pci_msix_table_bar.9 \ pci.9 pci_pending_msix.9 \ pci.9 pci_read_config.9 \ pci.9 pci_release_msi.9 \ pci.9 pci_remap_msix.9 \ pci.9 pci_restore_state.9 \ pci.9 pci_save_state.9 \ pci.9 pci_set_powerstate.9 \ pci.9 pci_set_max_read_req.9 \ pci.9 pci_write_config.9 \ pci.9 pcie_adjust_config.9 \ pci.9 pcie_flr.9 \ pci.9 pcie_max_completion_timeout.9 \ pci.9 pcie_read_config.9 \ pci.9 pcie_wait_for_pending_transactions.9 \ pci.9 pcie_write_config.9 MLINKS+=pci_iov_schema.9 pci_iov_schema_alloc_node.9 \ pci_iov_schema.9 pci_iov_schema_add_bool.9 \ pci_iov_schema.9 pci_iov_schema_add_string.9 \ pci_iov_schema.9 pci_iov_schema_add_uint8.9 \ pci_iov_schema.9 pci_iov_schema_add_uint16.9 \ pci_iov_schema.9 pci_iov_schema_add_uint32.9 \ pci_iov_schema.9 pci_iov_schema_add_uint64.9 \ pci_iov_schema.9 pci_iov_schema_add_unicast_mac.9 MLINKS+=pfil.9 pfil_add_hook.9 \ pfil.9 pfil_head_register.9 \ pfil.9 pfil_head_unregister.9 \ pfil.9 pfil_remove_hook.9 \ pfil.9 pfil_run_hooks.9 \ pfil.9 pfil_link.9 MLINKS+=pfind.9 zpfind.9 MLINKS+=PHOLD.9 PRELE.9 \ PHOLD.9 _PHOLD.9 \ PHOLD.9 _PRELE.9 \ PHOLD.9 PROC_ASSERT_HELD.9 \ PHOLD.9 PROC_ASSERT_NOT_HELD.9 MLINKS+=pmap_copy.9 pmap_copy_page.9 MLINKS+=pmap_extract.9 pmap_extract_and_hold.9 MLINKS+=pmap_kextract.9 vtophys.9 MLINKS+=pmap_is_modified.9 pmap_ts_referenced.9 MLINKS+=pmap_pinit.9 pmap_pinit0.9 MLINKS+=pmap_qenter.9 pmap_qremove.9 MLINKS+=pmap_quick_enter_page.9 pmap_quick_remove_page.9 MLINKS+=pmap_remove.9 pmap_remove_all.9 \ pmap_remove.9 pmap_remove_pages.9 MLINKS+=pmap_resident_count.9 pmap_wired_count.9 MLINKS+=pmap_zero_page.9 pmap_zero_area.9 MLINKS+=printf.9 log.9 \ printf.9 tprintf.9 \ printf.9 uprintf.9 \ printf.9 vlog.9 \ printf.9 vprintf.9 MLINKS+=priv.9 priv_check.9 \ priv.9 priv_check_cred.9 MLINKS+=prng.9 prng32.9 \ prng.9 prng32_bounded.9 \ prng.9 prng64.9 \ prng.9 prng64_bounded.9 MLINKS+=proc_rwmem.9 proc_readmem.9 \ proc_rwmem.9 proc_writemem.9 MLINKS+=psignal.9 pgsignal.9 \ psignal.9 tdsignal.9 MLINKS+=pwmbus.9 pwm.9 MLINKS+=random.9 arc4rand.9 \ random.9 arc4random.9 \ random.9 is_random_seeded.9 \ random.9 read_random.9 \ random.9 read_random_uio.9 \ random.9 srandom.9 MLINKS+=random_harvest.9 random_harvest_direct.9 \ random_harvest.9 random_harvest_fast.9 \ random_harvest.9 random_harvest_queue.9 MLINKS+=ratecheck.9 ppsratecheck.9 MLINKS+=refcount.9 refcount_acquire.9 \ refcount.9 refcount_acquire_checked.9 \ refcount.9 refcount_acquire_if_not_zero.9 \ refcount.9 refcount_init.9 \ refcount.9 refcount_load.9 \ refcount.9 refcount_release.9 \ refcount.9 refcount_release_if_last.9 \ refcount.9 refcount_release_if_not_last.9 MLINKS+=resource_int_value.9 resource_long_value.9 \ resource_int_value.9 resource_string_value.9 MLINKS+=rman.9 rman_activate_resource.9 \ rman.9 rman_adjust_resource.9 \ rman.9 rman_deactivate_resource.9 \ rman.9 rman_fini.9 \ rman.9 rman_first_free_region.9 \ rman.9 rman_get_bushandle.9 \ rman.9 rman_get_bustag.9 \ rman.9 rman_get_device.9 \ rman.9 rman_get_end.9 \ rman.9 rman_get_flags.9 \ rman.9 rman_get_mapping.9 \ rman.9 rman_get_rid.9 \ rman.9 rman_get_size.9 \ rman.9 rman_get_start.9 \ rman.9 rman_get_type.9 \ rman.9 rman_get_virtual.9 \ rman.9 rman_init.9 \ rman.9 rman_init_from_resource.9 \ rman.9 rman_is_region_manager.9 \ rman.9 rman_last_free_region.9 \ rman.9 rman_make_alignment_flags.9 \ rman.9 rman_manage_region.9 \ rman.9 rman_release_resource.9 \ rman.9 rman_reserve_resource.9 \ rman.9 rman_reserve_resource_bound.9 \ rman.9 rman_set_bushandle.9 \ rman.9 rman_set_bustag.9 \ rman.9 rman_set_mapping.9 \ rman.9 rman_set_rid.9 \ rman.9 rman_set_type.9 \ rman.9 rman_set_virtual.9 MLINKS+=rmlock.9 rm_assert.9 \ rmlock.9 rm_destroy.9 \ rmlock.9 rm_init.9 \ rmlock.9 rm_init_flags.9 \ rmlock.9 rm_rlock.9 \ rmlock.9 rm_runlock.9 \ rmlock.9 rm_sleep.9 \ rmlock.9 RM_SYSINIT.9 \ rmlock.9 RM_SYSINIT_FLAGS.9 \ rmlock.9 rm_try_rlock.9 \ rmlock.9 rm_wlock.9 \ rmlock.9 rm_wowned.9 \ rmlock.9 rm_wunlock.9 MLINKS+=runqueue.9 choosethread.9 \ runqueue.9 procrunnable.9 \ runqueue.9 remrunqueue.9 \ runqueue.9 setrunqueue.9 MLINKS+=rwlock.9 rw_assert.9 \ rwlock.9 rw_destroy.9 \ rwlock.9 rw_downgrade.9 \ rwlock.9 rw_init.9 \ rwlock.9 rw_init_flags.9 \ rwlock.9 rw_initialized.9 \ rwlock.9 rw_rlock.9 \ rwlock.9 rw_runlock.9 \ rwlock.9 rw_unlock.9 \ rwlock.9 rw_sleep.9 \ rwlock.9 RW_SYSINIT.9 \ rwlock.9 RW_SYSINIT_FLAGS.9 \ rwlock.9 rw_try_rlock.9 \ rwlock.9 rw_try_upgrade.9 \ rwlock.9 rw_try_wlock.9 \ rwlock.9 rw_wlock.9 \ rwlock.9 rw_wowned.9 \ rwlock.9 rw_wunlock.9 MLINKS+=sbuf.9 sbuf_bcat.9 \ sbuf.9 sbuf_bcopyin.9 \ sbuf.9 sbuf_bcpy.9 \ sbuf.9 sbuf_cat.9 \ sbuf.9 sbuf_clear.9 \ sbuf.9 sbuf_clear_flags.9 \ sbuf.9 sbuf_copyin.9 \ sbuf.9 sbuf_cpy.9 \ sbuf.9 sbuf_data.9 \ sbuf.9 sbuf_delete.9 \ sbuf.9 sbuf_done.9 \ sbuf.9 sbuf_error.9 \ sbuf.9 sbuf_finish.9 \ sbuf.9 sbuf_get_flags.9 \ sbuf.9 sbuf_hexdump.9 \ sbuf.9 sbuf_len.9 \ sbuf.9 sbuf_new.9 \ sbuf.9 sbuf_new_auto.9 \ sbuf.9 sbuf_new_for_sysctl.9 \ sbuf.9 sbuf_nl_terminate.9 \ sbuf.9 sbuf_printf.9 \ sbuf.9 sbuf_printf_drain.9 \ sbuf.9 sbuf_putbuf.9 \ sbuf.9 sbuf_putc.9 \ sbuf.9 sbuf_set_drain.9 \ sbuf.9 sbuf_set_flags.9 \ sbuf.9 sbuf_setpos.9 \ sbuf.9 sbuf_start_section.9 \ sbuf.9 sbuf_end_section.9 \ sbuf.9 sbuf_trim.9 \ sbuf.9 sbuf_vprintf.9 MLINKS+=scheduler.9 curpriority_cmp.9 \ scheduler.9 maybe_resched.9 \ scheduler.9 propagate_priority.9 \ scheduler.9 resetpriority.9 \ scheduler.9 roundrobin.9 \ scheduler.9 roundrobin_interval.9 \ scheduler.9 schedclock.9 \ scheduler.9 schedcpu.9 \ scheduler.9 sched_setup.9 \ scheduler.9 setrunnable.9 \ scheduler.9 updatepri.9 MLINKS+=SDT.9 SDT_PROVIDER_DECLARE.9 \ SDT.9 SDT_PROVIDER_DEFINE.9 \ SDT.9 SDT_PROBE_DECLARE.9 \ SDT.9 SDT_PROBE_DEFINE.9 \ SDT.9 SDT_PROBE.9 MLINKS+=securelevel_gt.9 securelevel_ge.9 MLINKS+=selrecord.9 seldrain.9 \ selrecord.9 selwakeup.9 MLINKS+=sema.9 sema_destroy.9 \ sema.9 sema_init.9 \ sema.9 sema_post.9 \ sema.9 sema_timedwait.9 \ sema.9 sema_trywait.9 \ sema.9 sema_value.9 \ sema.9 sema_wait.9 MLINKS+=seqc.9 seqc_consistent.9 \ seqc.9 seqc_read.9 \ seqc.9 seqc_write_begin.9 \ seqc.9 seqc_write_end.9 MLINKS+=sf_buf.9 sf_buf_alloc.9 \ sf_buf.9 sf_buf_free.9 \ sf_buf.9 sf_buf_kva.9 \ sf_buf.9 sf_buf_page.9 MLINKS+=sglist.9 sglist_alloc.9 \ sglist.9 sglist_append.9 \ sglist.9 sglist_append_bio.9 \ sglist.9 sglist_append_mbuf.9 \ sglist.9 sglist_append_mbuf_epg.9 \ sglist.9 sglist_append_phys.9 \ sglist.9 sglist_append_sglist.9 \ sglist.9 sglist_append_single_mbuf.9 \ sglist.9 sglist_append_uio.9 \ sglist.9 sglist_append_user.9 \ sglist.9 sglist_append_vmpages.9 \ sglist.9 sglist_build.9 \ sglist.9 sglist_clone.9 \ sglist.9 sglist_consume_uio.9 \ sglist.9 sglist_count.9 \ sglist.9 sglist_count_mbuf_epg.9 \ sglist.9 sglist_count_vmpages.9 \ sglist.9 sglist_free.9 \ sglist.9 sglist_hold.9 \ sglist.9 sglist_init.9 \ sglist.9 sglist_join.9 \ sglist.9 sglist_length.9 \ sglist.9 sglist_reset.9 \ sglist.9 sglist_slice.9 \ sglist.9 sglist_split.9 MLINKS+=shm_map.9 shm_unmap.9 MLINKS+=signal.9 cursig.9 \ signal.9 execsigs.9 \ signal.9 issignal.9 \ signal.9 killproc.9 \ signal.9 pgsigio.9 \ signal.9 postsig.9 \ signal.9 SETSETNEQ.9 \ signal.9 SETSETOR.9 \ signal.9 SIGADDSET.9 \ signal.9 SIG_CONTSIGMASK.9 \ signal.9 SIGDELSET.9 \ signal.9 SIGEMPTYSET.9 \ signal.9 sigexit.9 \ signal.9 SIGFILLSET.9 \ signal.9 siginit.9 \ signal.9 SIGISEMPTY.9 \ signal.9 SIGISMEMBER.9 \ signal.9 SIGNOTEMPTY.9 \ signal.9 signotify.9 \ signal.9 SIGPENDING.9 \ signal.9 SIGSETAND.9 \ signal.9 SIGSETCANTMASK.9 \ signal.9 SIGSETEQ.9 \ signal.9 SIGSETNAND.9 \ signal.9 SIG_STOPSIGMASK.9 \ signal.9 trapsignal.9 MLINKS+=sleep.9 msleep.9 \ sleep.9 msleep_sbt.9 \ sleep.9 msleep_spin.9 \ sleep.9 msleep_spin_sbt.9 \ sleep.9 pause.9 \ sleep.9 pause_sig.9 \ sleep.9 pause_sbt.9 \ sleep.9 tsleep.9 \ sleep.9 tsleep_sbt.9 \ sleep.9 wakeup.9 \ sleep.9 wakeup_one.9 \ sleep.9 wakeup_any.9 MLINKS+=sleepqueue.9 init_sleepqueues.9 \ sleepqueue.9 sleepq_abort.9 \ sleepqueue.9 sleepq_add.9 \ sleepqueue.9 sleepq_alloc.9 \ sleepqueue.9 sleepq_broadcast.9 \ sleepqueue.9 sleepq_free.9 \ sleepqueue.9 sleepq_lookup.9 \ sleepqueue.9 sleepq_lock.9 \ sleepqueue.9 sleepq_release.9 \ sleepqueue.9 sleepq_remove.9 \ sleepqueue.9 sleepq_set_timeout.9 \ sleepqueue.9 sleepq_set_timeout_sbt.9 \ sleepqueue.9 sleepq_signal.9 \ sleepqueue.9 sleepq_sleepcnt.9 \ sleepqueue.9 sleepq_timedwait.9 \ sleepqueue.9 sleepq_timedwait_sig.9 \ sleepqueue.9 sleepq_type.9 \ sleepqueue.9 sleepq_wait.9 \ sleepqueue.9 sleepq_wait_sig.9 MLINKS+=smr.9 smr_advance.9 \ smr.9 smr_create.9 \ smr.9 smr_destroy.9 \ smr.9 smr_enter.9 \ smr.9 smr_exit.9 \ smr.9 smr_poll.9 \ smr.9 smr_synchronize.9 \ smr.9 smr_wait.9 MLINKS+=socket.9 soabort.9 \ socket.9 soaccept.9 \ socket.9 sobind.9 \ socket.9 socheckuid.9 \ socket.9 soclose.9 \ socket.9 soconnect.9 \ socket.9 socreate.9 \ socket.9 sodisconnect.9 \ socket.9 sodtor_set.9 \ socket.9 sodupsockaddr.9 \ socket.9 sofree.9 \ socket.9 sogetopt.9 \ socket.9 sohasoutofband.9 \ socket.9 solisten.9 \ socket.9 solisten_proto.9 \ socket.9 solisten_proto_check.9 \ socket.9 sonewconn.9 \ socket.9 sooptcopyin.9 \ socket.9 sooptcopyout.9 \ socket.9 sopoll.9 \ socket.9 sopoll_generic.9 \ socket.9 soreceive.9 \ socket.9 soreceive_dgram.9 \ socket.9 soreceive_generic.9 \ socket.9 soreceive_stream.9 \ socket.9 soreserve.9 \ socket.9 sorflush.9 \ socket.9 sosend.9 \ socket.9 sosend_dgram.9 \ socket.9 sosend_generic.9 \ socket.9 sosetopt.9 \ socket.9 soshutdown.9 \ socket.9 sotoxsocket.9 \ socket.9 soupcall_clear.9 \ socket.9 soupcall_set.9 \ socket.9 sowakeup.9 MLINKS+=stack.9 stack_copy.9 \ stack.9 stack_create.9 \ stack.9 stack_destroy.9 \ stack.9 stack_print.9 \ stack.9 stack_print_ddb.9 \ stack.9 stack_print_short.9 \ stack.9 stack_print_short_ddb.9 \ stack.9 stack_put.9 \ stack.9 stack_save.9 \ stack.9 stack_sbuf_print.9 \ stack.9 stack_sbuf_print_ddb.9 \ stack.9 stack_zero.9 MLINKS+=store.9 subyte.9 \ store.9 suword.9 \ store.9 suword16.9 \ store.9 suword32.9 \ store.9 suword64.9 MLINKS+=swi.9 swi_add.9 \ swi.9 swi_remove.9 \ swi.9 swi_sched.9 MLINKS+=sx.9 sx_assert.9 \ sx.9 sx_destroy.9 \ sx.9 sx_downgrade.9 \ sx.9 sx_init.9 \ sx.9 sx_init_flags.9 \ sx.9 sx_sleep.9 \ sx.9 sx_slock.9 \ sx.9 sx_slock_sig.9 \ sx.9 sx_sunlock.9 \ sx.9 SX_SYSINIT.9 \ sx.9 SX_SYSINIT_FLAGS.9 \ sx.9 sx_try_slock.9 \ sx.9 sx_try_upgrade.9 \ sx.9 sx_try_xlock.9 \ sx.9 sx_unlock.9 \ sx.9 sx_xholder.9 \ sx.9 sx_xlock.9 \ sx.9 sx_xlock_sig.9 \ sx.9 sx_xlocked.9 \ sx.9 sx_xunlock.9 MLINKS+=syscall_helper_register.9 syscall_helper_unregister.9 \ syscall_helper_register.9 SYSCALL_INIT_HELPER.9 \ syscall_helper_register.9 SYSCALL_INIT_HELPER_COMPAT.9 \ syscall_helper_register.9 SYSCALL_INIT_HELPER_COMPAT_F.9 \ syscall_helper_register.9 SYSCALL_INIT_HELPER_F.9 MLINKS+=sysctl.9 SYSCTL_DECL.9 \ sysctl.9 SYSCTL_ADD_CONST_STRING.9 \ sysctl.9 SYSCTL_ADD_INT.9 \ sysctl.9 SYSCTL_ADD_LONG.9 \ sysctl.9 SYSCTL_ADD_NODE.9 \ sysctl.9 SYSCTL_ADD_NODE_WITH_LABEL.9 \ sysctl.9 SYSCTL_ADD_OPAQUE.9 \ sysctl.9 SYSCTL_ADD_PROC.9 \ sysctl.9 SYSCTL_ADD_QUAD.9 \ sysctl.9 SYSCTL_ADD_ROOT_NODE.9 \ sysctl.9 SYSCTL_ADD_S8.9 \ sysctl.9 SYSCTL_ADD_S16.9 \ sysctl.9 SYSCTL_ADD_S32.9 \ sysctl.9 SYSCTL_ADD_S64.9 \ sysctl.9 SYSCTL_ADD_STRING.9 \ sysctl.9 SYSCTL_ADD_STRUCT.9 \ sysctl.9 SYSCTL_ADD_TIMEVAL_SEC.9 \ sysctl.9 SYSCTL_ADD_U8.9 \ sysctl.9 SYSCTL_ADD_U16.9 \ sysctl.9 SYSCTL_ADD_U32.9 \ sysctl.9 SYSCTL_ADD_U64.9 \ sysctl.9 SYSCTL_ADD_UAUTO.9 \ sysctl.9 SYSCTL_ADD_UINT.9 \ sysctl.9 SYSCTL_ADD_ULONG.9 \ sysctl.9 SYSCTL_ADD_UMA_CUR.9 \ sysctl.9 SYSCTL_ADD_UMA_MAX.9 \ sysctl.9 SYSCTL_ADD_UQUAD.9 \ sysctl.9 SYSCTL_CHILDREN.9 \ sysctl.9 SYSCTL_STATIC_CHILDREN.9 \ sysctl.9 SYSCTL_NODE_CHILDREN.9 \ sysctl.9 SYSCTL_PARENT.9 \ sysctl.9 SYSCTL_INT.9 \ sysctl.9 SYSCTL_INT_WITH_LABEL.9 \ sysctl.9 SYSCTL_LONG.9 \ sysctl.9 sysctl_msec_to_ticks.9 \ sysctl.9 SYSCTL_NODE.9 \ sysctl.9 SYSCTL_NODE_WITH_LABEL.9 \ sysctl.9 SYSCTL_OPAQUE.9 \ sysctl.9 SYSCTL_PROC.9 \ sysctl.9 SYSCTL_QUAD.9 \ sysctl.9 SYSCTL_ROOT_NODE.9 \ sysctl.9 SYSCTL_S8.9 \ sysctl.9 SYSCTL_S16.9 \ sysctl.9 SYSCTL_S32.9 \ sysctl.9 SYSCTL_S64.9 \ sysctl.9 SYSCTL_STRING.9 \ sysctl.9 SYSCTL_STRUCT.9 \ sysctl.9 SYSCTL_TIMEVAL_SEC.9 \ sysctl.9 SYSCTL_U8.9 \ sysctl.9 SYSCTL_U16.9 \ sysctl.9 SYSCTL_U32.9 \ sysctl.9 SYSCTL_U64.9 \ sysctl.9 SYSCTL_UINT.9 \ sysctl.9 SYSCTL_ULONG.9 \ sysctl.9 SYSCTL_UMA_CUR.9 \ sysctl.9 SYSCTL_UMA_MAX.9 \ sysctl.9 SYSCTL_UQUAD.9 MLINKS+=sysctl_add_oid.9 sysctl_move_oid.9 \ sysctl_add_oid.9 sysctl_remove_oid.9 \ sysctl_add_oid.9 sysctl_remove_name.9 MLINKS+=sysctl_ctx_init.9 sysctl_ctx_entry_add.9 \ sysctl_ctx_init.9 sysctl_ctx_entry_del.9 \ sysctl_ctx_init.9 sysctl_ctx_entry_find.9 \ sysctl_ctx_init.9 sysctl_ctx_free.9 MLINKS+=SYSINIT.9 SYSUNINIT.9 MLINKS+=taskqueue.9 TASK_INIT.9 \ taskqueue.9 TASK_INITIALIZER.9 \ taskqueue.9 taskqueue_block.9 \ taskqueue.9 taskqueue_cancel.9 \ taskqueue.9 taskqueue_cancel_timeout.9 \ taskqueue.9 taskqueue_create.9 \ taskqueue.9 taskqueue_create_fast.9 \ taskqueue.9 TASKQUEUE_DECLARE.9 \ taskqueue.9 TASKQUEUE_DEFINE.9 \ taskqueue.9 TASKQUEUE_DEFINE_THREAD.9 \ taskqueue.9 taskqueue_drain.9 \ taskqueue.9 taskqueue_drain_all.9 \ taskqueue.9 taskqueue_drain_timeout.9 \ taskqueue.9 taskqueue_enqueue.9 \ taskqueue.9 taskqueue_enqueue_timeout.9 \ taskqueue.9 taskqueue_enqueue_timeout_sbt.9 \ taskqueue.9 TASKQUEUE_FAST_DEFINE.9 \ taskqueue.9 TASKQUEUE_FAST_DEFINE_THREAD.9 \ taskqueue.9 taskqueue_free.9 \ taskqueue.9 taskqueue_member.9 \ taskqueue.9 taskqueue_quiesce.9 \ taskqueue.9 taskqueue_run.9 \ taskqueue.9 taskqueue_set_callback.9 \ taskqueue.9 taskqueue_start_threads.9 \ taskqueue.9 taskqueue_start_threads_cpuset.9 \ taskqueue.9 taskqueue_start_threads_in_proc.9 \ taskqueue.9 taskqueue_unblock.9 \ taskqueue.9 TIMEOUT_TASK_INIT.9 MLINKS+=tcp_functions.9 register_tcp_functions.9 \ tcp_functions.9 register_tcp_functions_as_name.9 \ tcp_functions.9 register_tcp_functions_as_names.9 \ tcp_functions.9 deregister_tcp_functions.9 MLINKS+=time.9 boottime.9 \ time.9 time_second.9 \ time.9 time_uptime.9 MLINKS+=ucred.9 crcopy.9 \ ucred.9 crcopysafe.9 \ ucred.9 crdup.9 \ ucred.9 crfree.9 \ ucred.9 crget.9 \ ucred.9 crhold.9 \ ucred.9 crsetgroups.9 \ ucred.9 cru2x.9 MLINKS+=uidinfo.9 uifind.9 \ uidinfo.9 uifree.9 \ uidinfo.9 uihashinit.9 \ uidinfo.9 uihold.9 MLINKS+=uio.9 uiomove.9 \ uio.9 uiomove_frombuf.9 \ uio.9 uiomove_nofault.9 MLINKS+=unr.9 alloc_unr.9 \ unr.9 alloc_unrl.9 \ unr.9 alloc_unr_specific.9 \ unr.9 clear_unrhdr.9 \ unr.9 delete_unrhdr.9 \ unr.9 free_unr.9 \ unr.9 new_unrhdr.9 .if ${MK_USB} != "no" MAN+= usbdi.9 MLINKS+=usbdi.9 usbd_do_request.9 \ usbdi.9 usbd_do_request_flags.9 \ usbdi.9 usbd_errstr.9 \ usbdi.9 usbd_lookup_id_by_info.9 \ usbdi.9 usbd_lookup_id_by_uaa.9 \ usbdi.9 usbd_transfer_clear_stall.9 \ usbdi.9 usbd_transfer_drain.9 \ usbdi.9 usbd_transfer_pending.9 \ usbdi.9 usbd_transfer_poll.9 \ usbdi.9 usbd_transfer_setup.9 \ usbdi.9 usbd_transfer_start.9 \ usbdi.9 usbd_transfer_stop.9 \ usbdi.9 usbd_transfer_submit.9 \ usbdi.9 usbd_transfer_unsetup.9 \ usbdi.9 usbd_xfer_clr_flag.9 \ usbdi.9 usbd_xfer_frame_data.9 \ usbdi.9 usbd_xfer_frame_len.9 \ usbdi.9 usbd_xfer_get_frame.9 \ usbdi.9 usbd_xfer_get_priv.9 \ usbdi.9 usbd_xfer_is_stalled.9 \ usbdi.9 usbd_xfer_max_framelen.9 \ usbdi.9 usbd_xfer_max_frames.9 \ usbdi.9 usbd_xfer_max_len.9 \ usbdi.9 usbd_xfer_set_flag.9 \ usbdi.9 usbd_xfer_set_frame_data.9 \ usbdi.9 usbd_xfer_set_frame_len.9 \ usbdi.9 usbd_xfer_set_frame_offset.9 \ usbdi.9 usbd_xfer_set_frames.9 \ usbdi.9 usbd_xfer_set_interval.9 \ usbdi.9 usbd_xfer_set_priv.9 \ usbdi.9 usbd_xfer_set_stall.9 \ usbdi.9 usbd_xfer_set_timeout.9 \ usbdi.9 usbd_xfer_softc.9 \ usbdi.9 usbd_xfer_state.9 \ usbdi.9 usbd_xfer_status.9 \ usbdi.9 usb_fifo_alloc_buffer.9 \ usbdi.9 usb_fifo_attach.9 \ usbdi.9 usb_fifo_detach.9 \ usbdi.9 usb_fifo_free_buffer.9 \ usbdi.9 usb_fifo_get_data.9 \ usbdi.9 usb_fifo_get_data_buffer.9 \ usbdi.9 usb_fifo_get_data_error.9 \ usbdi.9 usb_fifo_get_data_linear.9 \ usbdi.9 usb_fifo_put_bytes_max.9 \ usbdi.9 usb_fifo_put_data.9 \ usbdi.9 usb_fifo_put_data_buffer.9 \ usbdi.9 usb_fifo_put_data_error.9 \ usbdi.9 usb_fifo_put_data_linear.9 \ usbdi.9 usb_fifo_reset.9 \ usbdi.9 usb_fifo_softc.9 \ usbdi.9 usb_fifo_wakeup.9 .endif MLINKS+=vfsconf.9 vfs_modevent.9 \ vfsconf.9 vfs_register.9 \ vfsconf.9 vfs_unregister.9 MLINKS+=vfs_getopt.9 vfs_copyopt.9 \ vfs_getopt.9 vfs_filteropt.9 \ vfs_getopt.9 vfs_flagopt.9 \ vfs_getopt.9 vfs_getopts.9 \ vfs_getopt.9 vfs_scanopt.9 \ vfs_getopt.9 vfs_setopt.9 \ vfs_getopt.9 vfs_setopt_part.9 \ vfs_getopt.9 vfs_setopts.9 MLINKS+=vhold.9 vdrop.9 \ vhold.9 vdropl.9 \ vhold.9 vholdl.9 MLINKS+=vmem.9 vmem_add.9 \ vmem.9 vmem_alloc.9 \ vmem.9 vmem_create.9 \ vmem.9 vmem_destroy.9 \ vmem.9 vmem_free.9 \ vmem.9 vmem_xalloc.9 \ vmem.9 vmem_xfree.9 MLINKS+=vm_map_lock.9 vm_map_lock_downgrade.9 \ vm_map_lock.9 vm_map_lock_read.9 \ vm_map_lock.9 vm_map_lock_upgrade.9 \ vm_map_lock.9 vm_map_trylock.9 \ vm_map_lock.9 vm_map_trylock_read.9 \ vm_map_lock.9 vm_map_unlock.9 \ vm_map_lock.9 vm_map_unlock_read.9 MLINKS+=vm_map_lookup.9 vm_map_lookup_done.9 MLINKS+=vm_map_max.9 vm_map_min.9 \ vm_map_max.9 vm_map_pmap.9 MLINKS+=vm_map_stack.9 vm_map_growstack.9 MLINKS+=vm_map_wire.9 vm_map_unwire.9 MLINKS+=vm_page_alloc.9 vm_page_alloc_after.9 \ vm_page_alloc.9 vm_page_alloc_contig.9 \ vm_page_alloc.9 vm_page_alloc_contig_domain.9 \ vm_page_alloc.9 vm_page_alloc_domain.9 \ vm_page_alloc.9 vm_page_alloc_domain_after.9 \ vm_page_alloc.9 vm_page_alloc_noobj.9 \ vm_page_alloc.9 vm_page_alloc_noobj_contig.9 \ vm_page_alloc.9 vm_page_alloc_noobj_contig_domain.9 \ vm_page_alloc.9 vm_page_alloc_noobj_domain.9 MLINKS+=vm_page_bits.9 vm_page_clear_dirty.9 \ vm_page_bits.9 vm_page_dirty.9 \ vm_page_bits.9 vm_page_is_valid.9 \ vm_page_bits.9 vm_page_set_invalid.9 \ vm_page_bits.9 vm_page_set_validclean.9 \ vm_page_bits.9 vm_page_test_dirty.9 \ vm_page_bits.9 vm_page_undirty.9 \ vm_page_bits.9 vm_page_zero_invalid.9 MLINKS+=vm_page_busy.9 vm_page_busied.9 \ vm_page_busy.9 vm_page_busy_downgrade.9 \ vm_page_busy.9 vm_page_busy_sleep.9 \ vm_page_busy.9 vm_page_sbusied.9 \ vm_page_busy.9 vm_page_sunbusy.9 \ vm_page_busy.9 vm_page_trysbusy.9 \ vm_page_busy.9 vm_page_tryxbusy.9 \ vm_page_busy.9 vm_page_xbusied.9 \ vm_page_busy.9 vm_page_xunbusy.9 \ vm_page_busy.9 vm_page_assert_sbusied.9 \ vm_page_busy.9 vm_page_assert_unbusied.9 \ vm_page_busy.9 vm_page_assert_xbusied.9 MLINKS+=vm_page_aflag.9 vm_page_aflag_clear.9 \ vm_page_aflag.9 vm_page_aflag_set.9 \ vm_page_aflag.9 vm_page_reference.9 MLINKS+=vm_page_free.9 vm_page_free_toq.9 \ vm_page_free.9 vm_page_free_zero.9 \ vm_page_free.9 vm_page_try_to_free.9 MLINKS+=vm_page_insert.9 vm_page_remove.9 MLINKS+=vm_page_wire.9 vm_page_unwire.9 \ vm_page_wire.9 vm_page_unwire_noq.9 \ vm_page_wire.9 vm_page_wire_mapped.9 MLINKS+=VOP_ACCESS.9 VOP_ACCESSX.9 MLINKS+=VOP_ATTRIB.9 VOP_GETATTR.9 \ VOP_ATTRIB.9 VOP_SETATTR.9 \ VOP_ATTRIB.9 VOP_STAT.9 MLINKS+=VOP_CREATE.9 VOP_MKDIR.9 \ VOP_CREATE.9 VOP_MKNOD.9 \ VOP_CREATE.9 VOP_SYMLINK.9 MLINKS+=VOP_FSYNC.9 VOP_FDATASYNC.9 MLINKS+=VOP_GETPAGES.9 VOP_PUTPAGES.9 MLINKS+=VOP_INACTIVE.9 VOP_RECLAIM.9 MLINKS+=VOP_INOTIFY.9 VOP_INOTIFY_ADD_WATCH.9 MLINKS+=VOP_LOCK.9 vn_lock.9 \ VOP_LOCK.9 VOP_ISLOCKED.9 \ VOP_LOCK.9 VOP_UNLOCK.9 MLINKS+=VOP_OPENCLOSE.9 VOP_CLOSE.9 \ VOP_OPENCLOSE.9 VOP_OPEN.9 MLINKS+=VOP_RDWR.9 VOP_READ.9 \ VOP_RDWR.9 VOP_WRITE.9 MLINKS+=VOP_REMOVE.9 VOP_RMDIR.9 MLINKS+=VNET.9 VIMAGE.9 -MLINKS+=vref.9 VREF.9 \ - vref.9 vrefl.9 +MLINKS+=vref.9 vrefl.9 MLINKS+=vrele.9 vput.9 \ vrele.9 vunref.9 MLINKS+=vslock.9 vsunlock.9 MLINKS+=zone.9 uma.9 \ zone.9 uma_prealloc.9 \ zone.9 uma_reclaim.9 \ zone.9 uma_zalloc.9 \ zone.9 uma_zalloc_arg.9 \ zone.9 uma_zalloc_domain.9 \ zone.9 uma_zalloc_pcpu.9 \ zone.9 uma_zalloc_pcpu_arg.9 \ zone.9 uma_zcache_create.9 \ zone.9 uma_zcreate.9 \ zone.9 uma_zdestroy.9 \ zone.9 uma_zfree.9 \ zone.9 uma_zfree_arg.9 \ zone.9 uma_zfree_pcpu.9 \ zone.9 uma_zfree_pcpu_arg.9 \ zone.9 uma_zone_get_cur.9 \ zone.9 uma_zone_get_max.9 \ zone.9 uma_zone_reclaim.9 \ zone.9 uma_zone_reserve.9 \ zone.9 uma_zone_reserve_kva.9 \ zone.9 uma_zone_set_allocf.9 \ zone.9 uma_zone_set_freef.9 \ zone.9 uma_zone_set_max.9 \ zone.9 uma_zone_set_maxaction.9 \ zone.9 uma_zone_set_maxcache.9 \ zone.9 uma_zone_set_warning.9 \ zone.9 uma_zsecond_create.9 # This makes more sense for amd64 and i386 but # we decide to install all manpages in all architectures _superio.9= superio.9 MLINKS+=superio.9 superio_devid.9 \ superio.9 superio_dev_disable.9 \ superio.9 superio_dev_enable.9 \ superio.9 superio_dev_enabled.9 \ superio.9 superio_find_dev.9 \ superio.9 superio_get_dma.9 \ superio.9 superio_get_iobase.9 \ superio.9 superio_get_irq.9 \ superio.9 superio_get_ldn.9 \ superio.9 superio_get_type.9 \ superio.9 superio_read.9 \ superio.9 superio_revid.9 \ superio.9 superio_vendor.9 \ superio.9 superio_write.9 .include diff --git a/sys/fs/cd9660/cd9660_lookup.c b/sys/fs/cd9660/cd9660_lookup.c index 75fcdc9152cd..4d0bf73ab235 100644 --- a/sys/fs/cd9660/cd9660_lookup.c +++ b/sys/fs/cd9660/cd9660_lookup.c @@ -1,463 +1,463 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension * Support code is derived from software contributed to Berkeley * by Atsushi Murai (amurai@spec.co.jp). * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 #include #include #include #include #include #include #include #include #include struct cd9660_ino_alloc_arg { ino_t ino; ino_t i_ino; struct iso_directory_record *ep; }; static int cd9660_ino_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp) { struct cd9660_ino_alloc_arg *dd_arg; dd_arg = arg; return (cd9660_vget_internal(mp, dd_arg->i_ino, lkflags, vpp, dd_arg->i_ino != dd_arg->ino, dd_arg->ep)); } /* * Convert a component of a pathname into a pointer to a locked inode. * This is a very central and rather complicated routine. * If the filesystem is not maintained in a strict tree hierarchy, * this can result in a deadlock situation (see comments in code below). * * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on * whether the name is to be looked up, created, renamed, or deleted. * When CREATE, RENAME, or DELETE is specified, information usable in * creating, renaming, or deleting a directory entry may be calculated. * If flag has LOCKPARENT or'ed into it and the target of the pathname * exists, lookup returns both the target and its parent directory locked. * When creating or renaming and LOCKPARENT is specified, the target may * not be ".". When deleting and LOCKPARENT is specified, the target may * be "."., but the caller must check to ensure it does an vrele and iput * instead of two iputs. * * Overall outline of ufs_lookup: * * search for name in directory, to found or notfound * notfound: * if creating, return locked directory, leaving info on available slots * else return error * found: * if at end of path and deleting, return information to allow delete * if at end of path and rewriting (RENAME and LOCKPARENT), lock target * inode and return info to allow rewrite * if not at end, add name to cache; if at end and neither creating * nor deleting, add name to cache * * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked. */ int cd9660_lookup(struct vop_cachedlookup_args *ap) { struct vnode *vdp; /* vnode for directory being searched */ struct iso_node *dp; /* inode for directory being searched */ struct iso_mnt *imp; /* filesystem that directory is in */ struct buf *bp; /* a buffer of directory entries */ struct iso_directory_record *ep;/* the current directory entry */ struct iso_directory_record *ep2;/* copy of current directory entry */ int entryoffsetinblock; /* offset of ep in bp's buffer */ int saveoffset = 0; /* offset of last directory entry in dir */ doff_t i_diroff; /* cached i_diroff value. */ doff_t i_offset; /* cached i_offset value. */ int numdirpasses; /* strategy for directory search */ doff_t endsearch; /* offset to end directory search */ struct vnode *pdp; /* saved dp during symlink work */ struct vnode *tdp; /* returned by cd9660_vget_internal */ struct cd9660_ino_alloc_arg dd_arg; u_long bmask; /* block offset mask */ int error; ino_t ino, i_ino; int ltype, reclen; u_short namelen; int isoflags; char altname[NAME_MAX]; int res; int assoc, len; char *name; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; uint64_t flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; ep2 = ep = NULL; bp = NULL; *vpp = NULL; vdp = ap->a_dvp; dp = VTOI(vdp); imp = dp->i_mnt; /* * We now have a segment name to search for, and a directory to search. */ ino = reclen = 0; i_diroff = dp->i_diroff; len = cnp->cn_namelen; name = cnp->cn_nameptr; /* * A leading `=' means, we are looking for an associated file */ if ((assoc = (imp->iso_ftype != ISO_FTYPE_RRIP && *name == ASSOCCHAR))) { len--; name++; } /* * If there is cached information on a previous search of * this directory, pick up where we last left off. * We cache only lookups as these are the most common * and have the greatest payoff. Caching CREATE has little * benefit as it usually must search the entire directory * to determine that the entry does not exist. Caching the * location of the last DELETE or RENAME has not reduced * profiling time and hence has been removed in the interest * of simplicity. */ bmask = imp->im_bmask; if (nameiop != LOOKUP || i_diroff == 0 || i_diroff > dp->i_size) { entryoffsetinblock = 0; i_offset = 0; numdirpasses = 1; } else { i_offset = i_diroff; if ((entryoffsetinblock = i_offset & bmask) && (error = cd9660_blkatoff(vdp, (off_t)i_offset, NULL, &bp))) return (error); numdirpasses = 2; nchstats.ncs_2passes++; } endsearch = dp->i_size; searchloop: while (i_offset < endsearch) { /* * If offset is on a block boundary, * read the next directory block. * Release previous if it exists. */ if ((i_offset & bmask) == 0) { if (bp != NULL) brelse(bp); if ((error = cd9660_blkatoff(vdp, (off_t)i_offset, NULL, &bp)) != 0) return (error); entryoffsetinblock = 0; } /* * Get pointer to next entry. */ ep = (struct iso_directory_record *) ((char *)bp->b_data + entryoffsetinblock); reclen = isonum_711(ep->length); if (reclen == 0) { /* skip to next block, if any */ i_offset = (i_offset & ~bmask) + imp->logical_block_size; continue; } if (reclen < ISO_DIRECTORY_RECORD_SIZE) /* illegal entry, stop */ break; if (entryoffsetinblock + reclen > imp->logical_block_size) /* entries are not allowed to cross boundaries */ break; namelen = isonum_711(ep->name_len); isoflags = isonum_711(imp->iso_ftype == ISO_FTYPE_HIGH_SIERRA? &ep->date[6]: ep->flags); if (reclen < ISO_DIRECTORY_RECORD_SIZE + namelen) /* illegal entry, stop */ break; /* * Check for a name match. */ switch (imp->iso_ftype) { default: if (!(isoflags & 4) == !assoc) { if ((len == 1 && *name == '.') || (flags & ISDOTDOT)) { if (namelen == 1 && ep->name[0] == ((flags & ISDOTDOT) ? 1 : 0)) { /* * Save directory entry's inode number and * release directory buffer. */ i_ino = isodirino(ep, imp); goto found; } if (namelen != 1 || ep->name[0] != 0) goto notfound; } else if (!(res = isofncmp(name, len, ep->name, namelen, imp->joliet_level, imp->im_flags, imp->im_d2l, imp->im_l2d))) { if (isoflags & 2) ino = isodirino(ep, imp); else ino = dbtob(bp->b_blkno) + entryoffsetinblock; saveoffset = i_offset; } else if (ino) goto foundino; #ifdef NOSORTBUG /* On some CDs directory entries are not sorted correctly */ else if (res < 0) goto notfound; else if (res > 0 && numdirpasses == 2) numdirpasses++; #endif } break; case ISO_FTYPE_RRIP: if (isonum_711(ep->flags)&2) ino = isodirino(ep, imp); else ino = dbtob(bp->b_blkno) + entryoffsetinblock; i_ino = ino; cd9660_rrip_getname(ep, altname, &namelen, &i_ino, imp); if (namelen == cnp->cn_namelen && !bcmp(name,altname,namelen)) goto found; ino = 0; break; } i_offset += reclen; entryoffsetinblock += reclen; } if (ino) { foundino: i_ino = ino; if (saveoffset != i_offset) { if (lblkno(imp, i_offset) != lblkno(imp, saveoffset)) { if (bp != NULL) brelse(bp); if ((error = cd9660_blkatoff(vdp, (off_t)saveoffset, NULL, &bp)) != 0) return (error); } entryoffsetinblock = saveoffset & bmask; ep = (struct iso_directory_record *) ((char *)bp->b_data + entryoffsetinblock); reclen = isonum_711(ep->length); i_offset = saveoffset; } goto found; } notfound: /* * If we started in the middle of the directory and failed * to find our target, we must check the beginning as well. */ if (numdirpasses == 2) { numdirpasses--; i_offset = 0; endsearch = i_diroff; goto searchloop; } if (bp != NULL) brelse(bp); /* * Insert name into cache (as non-existent) if appropriate. */ if (cnp->cn_flags & MAKEENTRY) cache_enter(vdp, *vpp, cnp); if (nameiop == CREATE || nameiop == RENAME) return (EROFS); return (ENOENT); found: if (numdirpasses == 2) nchstats.ncs_pass2++; /* * Found component in pathname. * If the final component of path name, save information * in the cache as to where the entry was found. */ if ((flags & ISLASTCN) && nameiop == LOOKUP) dp->i_diroff = i_offset; /* * Step through the translation in the name. We do not `vput' the * directory because we may need it again if a symbolic link * is relative to the current directory. Instead we save it * unlocked as "pdp". We must get the target inode before unlocking * the directory to insure that the inode will not be removed * before we get it. We prevent deadlock by always fetching * inodes from the root, moving down the directory tree. Thus * when following backward pointers ".." we must unlock the * parent directory before getting the requested directory. * There is a potential race condition here if both the current * and parent directories are removed before the `vget' for the * inode associated with ".." returns. We hope that this occurs * infrequently since we cannot avoid this race condition without * implementing a sophisticated deadlock detection algorithm. * Note also that this simple deadlock detection scheme will not * work if the filesystem has any hard links other than ".." * that point backwards in the directory structure. */ pdp = vdp; /* * Make a copy of the directory entry for non "." lookups so * we can drop the buffer before calling vget() to avoid a * lock order reversal between the vnode lock and the buffer * lock. */ if (dp->i_number != i_ino) { ep2 = malloc(reclen, M_TEMP, M_WAITOK); memcpy(ep2, ep, reclen); ep = ep2; } brelse(bp); /* * If ino is different from i_ino, * it's a relocated directory. */ if (flags & ISDOTDOT) { dd_arg.ino = ino; dd_arg.i_ino = i_ino; dd_arg.ep = ep; error = vn_vget_ino_gen(pdp, cd9660_ino_alloc, &dd_arg, cnp->cn_lkflags, &tdp); free(ep2, M_TEMP); if (error != 0) return (error); *vpp = tdp; } else if (dp->i_number == i_ino) { - VREF(vdp); /* we want ourself, ie "." */ + vref(vdp); /* we want ourself, ie "." */ /* * When we lookup "." we still can be asked to lock it * differently. */ ltype = cnp->cn_lkflags & LK_TYPE_MASK; if (ltype != VOP_ISLOCKED(vdp)) { if (ltype == LK_EXCLUSIVE) vn_lock(vdp, LK_UPGRADE | LK_RETRY); else /* if (ltype == LK_SHARED) */ vn_lock(vdp, LK_DOWNGRADE | LK_RETRY); } *vpp = vdp; } else { error = cd9660_vget_internal(vdp->v_mount, i_ino, cnp->cn_lkflags, &tdp, i_ino != ino, ep); free(ep2, M_TEMP); if (error) return (error); *vpp = tdp; } /* * Insert name into cache if appropriate. */ if (cnp->cn_flags & MAKEENTRY) cache_enter(vdp, *vpp, cnp); return (0); } /* * Return buffer with the contents of block "offset" from the beginning of * directory "ip". If "res" is non-zero, fill it in with a pointer to the * remaining space in the directory. */ int cd9660_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp) { struct iso_node *ip; struct iso_mnt *imp; struct buf *bp; daddr_t lbn; int bsize, bshift, error; ip = VTOI(vp); imp = ip->i_mnt; lbn = lblkno(imp, offset); bsize = blksize(imp, ip, lbn); bshift = imp->im_bshift; if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) { brelse(bp); *bpp = NULL; return (error); } /* * We must BMAP the buffer because the directory code may use b_blkno * to calculate the inode for certain types of directory entries. * We could get away with not doing it before we VMIO-backed the * directories because the buffers would get freed atomically with * the invalidation of their data. But with VMIO-backed buffers * the buffers may be freed and then later reconstituted - and the * reconstituted buffer will have no knowledge of b_blkno. */ if (bp->b_blkno == bp->b_lblkno) { bp->b_blkno = (ip->iso_start + bp->b_lblkno) << (bshift - DEV_BSHIFT); } if (res) *res = (char *)bp->b_data + blkoff(imp, offset); *bpp = bp; return (0); } diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index 590e04ac9aa5..caadf257b8ad 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -1,2150 +1,2150 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2000-2004 * Poul-Henning Kamp. All rights reserved. * Copyright (c) 1989, 1992-1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by * Jan-Simon Pendry. * * 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. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 */ /* * TODO: * mkdir: want it ? */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct vop_vector devfs_vnodeops; static struct vop_vector devfs_specops; static const struct fileops devfs_ops_f; #include #include #include #include #include #include static MALLOC_DEFINE(M_CDEVPDATA, "DEVFSP", "Metainfo for cdev-fp data"); struct mtx devfs_de_interlock; MTX_SYSINIT(devfs_de_interlock, &devfs_de_interlock, "devfs interlock", MTX_DEF); struct mtx cdevpriv_mtx; MTX_SYSINIT(cdevpriv_mtx, &cdevpriv_mtx, "cdevpriv lock", MTX_DEF); SYSCTL_DECL(_vfs_devfs); static int devfs_dotimes; SYSCTL_INT(_vfs_devfs, OID_AUTO, dotimes, CTLFLAG_RW, &devfs_dotimes, 0, "Update timestamps on DEVFS with default precision"); /* * Update devfs node timestamp. Note that updates are unlocked and * stat(2) could see partially updated times. */ static void devfs_timestamp(struct timespec *tsp) { time_t ts; if (devfs_dotimes) { vfs_timestamp(tsp); } else { ts = time_second; if (tsp->tv_sec != ts) { tsp->tv_sec = ts; tsp->tv_nsec = 0; } } } static int devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp, int *ref) { *dswp = devvn_refthread(fp->f_vnode, devp, ref); if (*dswp == NULL || *devp != fp->f_data) { if (*dswp != NULL) dev_relthread(*devp, *ref); return (ENXIO); } KASSERT((*devp)->si_refcount > 0, ("devfs: un-referenced struct cdev *(%s)", devtoname(*devp))); if (*dswp == NULL) return (ENXIO); curthread->td_fpop = fp; return (0); } int devfs_get_cdevpriv(void **datap) { struct file *fp; struct cdev_privdata *p; int error; fp = curthread->td_fpop; if (fp == NULL) return (EBADF); p = fp->f_cdevpriv; if (p != NULL) { error = 0; *datap = p->cdpd_data; } else error = ENOENT; return (error); } int devfs_set_cdevpriv(void *priv, d_priv_dtor_t *priv_dtr) { struct file *fp; struct cdev_priv *cdp; struct cdev_privdata *p; int error; fp = curthread->td_fpop; if (fp == NULL) return (ENOENT); cdp = cdev2priv((struct cdev *)fp->f_data); p = malloc(sizeof(struct cdev_privdata), M_CDEVPDATA, M_WAITOK); p->cdpd_data = priv; p->cdpd_dtr = priv_dtr; p->cdpd_fp = fp; mtx_lock(&cdevpriv_mtx); if (fp->f_cdevpriv == NULL) { LIST_INSERT_HEAD(&cdp->cdp_fdpriv, p, cdpd_list); fp->f_cdevpriv = p; mtx_unlock(&cdevpriv_mtx); error = 0; } else { mtx_unlock(&cdevpriv_mtx); free(p, M_CDEVPDATA); error = EBUSY; } return (error); } int devfs_foreach_cdevpriv(struct cdev *dev, int (*cb)(void *data, void *arg), void *arg) { struct cdev_priv *cdp; struct cdev_privdata *p; int error; cdp = cdev2priv(dev); error = 0; mtx_lock(&cdevpriv_mtx); LIST_FOREACH(p, &cdp->cdp_fdpriv, cdpd_list) { error = cb(p->cdpd_data, arg); if (error != 0) break; } mtx_unlock(&cdevpriv_mtx); return (error); } void devfs_destroy_cdevpriv(struct cdev_privdata *p) { mtx_assert(&cdevpriv_mtx, MA_OWNED); KASSERT(p->cdpd_fp->f_cdevpriv == p, ("devfs_destoy_cdevpriv %p != %p", p->cdpd_fp->f_cdevpriv, p)); p->cdpd_fp->f_cdevpriv = NULL; LIST_REMOVE(p, cdpd_list); mtx_unlock(&cdevpriv_mtx); (p->cdpd_dtr)(p->cdpd_data); free(p, M_CDEVPDATA); } static void devfs_fpdrop(struct file *fp) { struct cdev_privdata *p; mtx_lock(&cdevpriv_mtx); if ((p = fp->f_cdevpriv) == NULL) { mtx_unlock(&cdevpriv_mtx); return; } devfs_destroy_cdevpriv(p); } void devfs_clear_cdevpriv(void) { struct file *fp; fp = curthread->td_fpop; if (fp == NULL) return; devfs_fpdrop(fp); } static void devfs_usecount_add(struct vnode *vp) { struct devfs_dirent *de; struct cdev *dev; mtx_lock(&devfs_de_interlock); VI_LOCK(vp); VNPASS(vp->v_type == VCHR || vp->v_type == VBAD, vp); if (VN_IS_DOOMED(vp)) { goto out_unlock; } de = vp->v_data; dev = vp->v_rdev; MPASS(de != NULL); MPASS(dev != NULL); dev->si_usecount++; de->de_usecount++; out_unlock: VI_UNLOCK(vp); mtx_unlock(&devfs_de_interlock); } static void devfs_usecount_subl(struct vnode *vp) { struct devfs_dirent *de; struct cdev *dev; mtx_assert(&devfs_de_interlock, MA_OWNED); ASSERT_VI_LOCKED(vp, __func__); VNPASS(vp->v_type == VCHR || vp->v_type == VBAD, vp); de = vp->v_data; dev = vp->v_rdev; if (de == NULL) return; if (dev == NULL) { MPASS(de->de_usecount == 0); return; } if (dev->si_usecount < de->de_usecount) panic("%s: si_usecount underflow for dev %p " "(has %ld, dirent has %d)\n", __func__, dev, dev->si_usecount, de->de_usecount); if (VN_IS_DOOMED(vp)) { dev->si_usecount -= de->de_usecount; de->de_usecount = 0; } else { if (de->de_usecount == 0) panic("%s: de_usecount underflow for dev %p\n", __func__, dev); dev->si_usecount--; de->de_usecount--; } } static void devfs_usecount_sub(struct vnode *vp) { mtx_lock(&devfs_de_interlock); VI_LOCK(vp); devfs_usecount_subl(vp); VI_UNLOCK(vp); mtx_unlock(&devfs_de_interlock); } static int devfs_usecountl(struct vnode *vp) { VNPASS(vp->v_type == VCHR, vp); mtx_assert(&devfs_de_interlock, MA_OWNED); ASSERT_VI_LOCKED(vp, __func__); return (vp->v_rdev->si_usecount); } int devfs_usecount(struct vnode *vp) { int count; VNPASS(vp->v_type == VCHR, vp); mtx_lock(&devfs_de_interlock); VI_LOCK(vp); count = devfs_usecountl(vp); VI_UNLOCK(vp); mtx_unlock(&devfs_de_interlock); return (count); } void devfs_ctty_ref(struct vnode *vp) { vrefact(vp); devfs_usecount_add(vp); } void devfs_ctty_unref(struct vnode *vp) { devfs_usecount_sub(vp); vrele(vp); } /* * On success devfs_populate_vp() returns with dmp->dm_lock held. */ static int devfs_populate_vp(struct vnode *vp) { struct devfs_dirent *de; struct devfs_mount *dmp; int locked; ASSERT_VOP_LOCKED(vp, "devfs_populate_vp"); dmp = VFSTODEVFS(vp->v_mount); if (!devfs_populate_needed(dmp)) { sx_xlock(&dmp->dm_lock); goto out_nopopulate; } locked = VOP_ISLOCKED(vp); sx_xlock(&dmp->dm_lock); DEVFS_DMP_HOLD(dmp); /* Can't call devfs_populate() with the vnode lock held. */ VOP_UNLOCK(vp); devfs_populate(dmp); sx_xunlock(&dmp->dm_lock); vn_lock(vp, locked | LK_RETRY); sx_xlock(&dmp->dm_lock); if (DEVFS_DMP_DROP(dmp)) { sx_xunlock(&dmp->dm_lock); devfs_unmount_final(dmp); return (ERESTART); } out_nopopulate: if (VN_IS_DOOMED(vp)) { sx_xunlock(&dmp->dm_lock); return (ERESTART); } de = vp->v_data; KASSERT(de != NULL, ("devfs_populate_vp: vp->v_data == NULL but vnode not doomed")); if ((de->de_flags & DE_DOOMED) != 0) { sx_xunlock(&dmp->dm_lock); return (ERESTART); } return (0); } static int devfs_vptocnp(struct vop_vptocnp_args *ap) { struct vnode *vp = ap->a_vp; struct vnode **dvp = ap->a_vpp; struct devfs_mount *dmp; char *buf = ap->a_buf; size_t *buflen = ap->a_buflen; struct devfs_dirent *dd, *de; int i, error; dmp = VFSTODEVFS(vp->v_mount); error = devfs_populate_vp(vp); if (error != 0) return (error); if (vp->v_type != VCHR && vp->v_type != VDIR) { error = ENOENT; goto finished; } dd = vp->v_data; if (vp->v_type == VDIR && dd == dmp->dm_rootdir) { *dvp = vp; vref(*dvp); goto finished; } i = *buflen; i -= dd->de_dirent->d_namlen; if (i < 0) { error = ENOMEM; goto finished; } bcopy(dd->de_dirent->d_name, buf + i, dd->de_dirent->d_namlen); *buflen = i; de = devfs_parent_dirent(dd); if (de == NULL) { error = ENOENT; goto finished; } mtx_lock(&devfs_de_interlock); *dvp = de->de_vnode; if (*dvp != NULL) { VI_LOCK(*dvp); mtx_unlock(&devfs_de_interlock); vholdl(*dvp); VI_UNLOCK(*dvp); vref(*dvp); vdrop(*dvp); } else { mtx_unlock(&devfs_de_interlock); error = ENOENT; } finished: sx_xunlock(&dmp->dm_lock); return (error); } /* * Construct the fully qualified path name relative to the mountpoint. * If a NULL cnp is provided, no '/' is appended to the resulting path. */ char * devfs_fqpn(char *buf, struct devfs_mount *dmp, struct devfs_dirent *dd, struct componentname *cnp) { int i; struct devfs_dirent *de; sx_assert(&dmp->dm_lock, SA_LOCKED); i = SPECNAMELEN; buf[i] = '\0'; if (cnp != NULL) i -= cnp->cn_namelen; if (i < 0) return (NULL); if (cnp != NULL) bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen); de = dd; while (de != dmp->dm_rootdir) { if (cnp != NULL || i < SPECNAMELEN) { i--; if (i < 0) return (NULL); buf[i] = '/'; } i -= de->de_dirent->d_namlen; if (i < 0) return (NULL); bcopy(de->de_dirent->d_name, buf + i, de->de_dirent->d_namlen); de = devfs_parent_dirent(de); if (de == NULL) return (NULL); } return (buf + i); } static int devfs_allocv_drop_refs(int drop_dm_lock, struct devfs_mount *dmp, struct devfs_dirent *de) { int not_found; not_found = 0; if (de->de_flags & DE_DOOMED) not_found = 1; if (DEVFS_DE_DROP(de)) { KASSERT(not_found == 1, ("DEVFS de dropped but not doomed")); devfs_dirent_free(de); } if (DEVFS_DMP_DROP(dmp)) { KASSERT(not_found == 1, ("DEVFS mount struct freed before dirent")); not_found = 2; sx_xunlock(&dmp->dm_lock); devfs_unmount_final(dmp); } if (not_found == 1 || (drop_dm_lock && not_found != 2)) sx_unlock(&dmp->dm_lock); return (not_found); } /* * devfs_allocv shall be entered with dmp->dm_lock held, and it drops * it on return. */ int devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode, struct vnode **vpp) { int error; struct vnode *vp; struct cdev *dev; struct devfs_mount *dmp; struct cdevsw *dsw; enum vgetstate vs; dmp = VFSTODEVFS(mp); if (de->de_flags & DE_DOOMED) { sx_xunlock(&dmp->dm_lock); return (ENOENT); } loop: DEVFS_DE_HOLD(de); DEVFS_DMP_HOLD(dmp); mtx_lock(&devfs_de_interlock); vp = de->de_vnode; if (vp != NULL) { vs = vget_prep(vp); mtx_unlock(&devfs_de_interlock); sx_xunlock(&dmp->dm_lock); vget_finish(vp, lockmode | LK_RETRY, vs); sx_xlock(&dmp->dm_lock); if (devfs_allocv_drop_refs(0, dmp, de)) { vput(vp); return (ENOENT); } else if (VN_IS_DOOMED(vp)) { mtx_lock(&devfs_de_interlock); if (de->de_vnode == vp) { de->de_vnode = NULL; vp->v_data = NULL; } mtx_unlock(&devfs_de_interlock); vput(vp); goto loop; } sx_xunlock(&dmp->dm_lock); *vpp = vp; return (0); } mtx_unlock(&devfs_de_interlock); if (de->de_dirent->d_type == DT_CHR) { if (!(de->de_cdp->cdp_flags & CDP_ACTIVE)) { devfs_allocv_drop_refs(1, dmp, de); return (ENOENT); } dev = &de->de_cdp->cdp_c; } else { dev = NULL; } error = getnewvnode("devfs", mp, &devfs_vnodeops, &vp); if (error != 0) { devfs_allocv_drop_refs(1, dmp, de); printf("devfs_allocv: failed to allocate new vnode\n"); return (error); } if (de->de_dirent->d_type == DT_CHR) { vp->v_type = VCHR; VI_LOCK(vp); dev_lock(); dev_refl(dev); /* XXX: v_rdev should be protect by vnode lock */ vp->v_rdev = dev; VNPASS(vp->v_usecount == 1, vp); /* Special casing of ttys for deadfs. Probably redundant. */ dsw = dev->si_devsw; if (dsw != NULL && (dsw->d_flags & D_TTY) != 0) vp->v_vflag |= VV_ISTTY; dev_unlock(); VI_UNLOCK(vp); if ((dev->si_flags & SI_ETERNAL) != 0) vp->v_vflag |= VV_ETERNALDEV; vp->v_op = &devfs_specops; } else if (de->de_dirent->d_type == DT_DIR) { vp->v_type = VDIR; } else if (de->de_dirent->d_type == DT_LNK) { vp->v_type = VLNK; } else { vp->v_type = VBAD; } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_NOWITNESS); VN_LOCK_ASHARE(vp); mtx_lock(&devfs_de_interlock); vp->v_data = de; de->de_vnode = vp; mtx_unlock(&devfs_de_interlock); error = insmntque1(vp, mp); if (error != 0) { mtx_lock(&devfs_de_interlock); vp->v_data = NULL; de->de_vnode = NULL; mtx_unlock(&devfs_de_interlock); vgone(vp); vput(vp); (void) devfs_allocv_drop_refs(1, dmp, de); return (error); } if (devfs_allocv_drop_refs(0, dmp, de)) { vgone(vp); vput(vp); return (ENOENT); } #ifdef MAC mac_devfs_vnode_associate(mp, de, vp); #endif sx_xunlock(&dmp->dm_lock); vn_set_state(vp, VSTATE_CONSTRUCTED); *vpp = vp; return (0); } static int devfs_access(struct vop_access_args *ap) { struct vnode *vp = ap->a_vp; struct devfs_dirent *de; struct proc *p; int error; de = vp->v_data; if (vp->v_type == VDIR) de = de->de_dir; error = vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid, ap->a_accmode, ap->a_cred); if (error == 0) return (0); if (error != EACCES) return (error); p = ap->a_td->td_proc; /* We do, however, allow access to the controlling terminal */ PROC_LOCK(p); if (!(p->p_flag & P_CONTROLT)) { PROC_UNLOCK(p); return (error); } if (p->p_session->s_ttydp == de->de_cdp) error = 0; PROC_UNLOCK(p); return (error); } _Static_assert(((FMASK | FCNTLFLAGS) & (FLASTCLOSE | FREVOKE)) == 0, "devfs-only flag reuse failed"); static int devfs_close(struct vop_close_args *ap) { struct vnode *vp = ap->a_vp, *oldvp; struct thread *td = ap->a_td; struct proc *p; struct cdev *dev = vp->v_rdev; struct cdevsw *dsw; struct devfs_dirent *de = vp->v_data; int dflags, error, ref, vp_locked; /* * XXX: Don't call d_close() if we were called because of * XXX: insmntque() failure. */ if (vp->v_data == NULL) return (0); /* * Hack: a tty device that is a controlling terminal * has a reference from the session structure. * We cannot easily tell that a character device is * a controlling terminal, unless it is the closing * process' controlling terminal. In that case, * if the reference count is 2 (this last descriptor * plus the session), release the reference from the session. */ if (de->de_usecount == 2 && td != NULL) { p = td->td_proc; PROC_LOCK(p); if (vp == p->p_session->s_ttyvp) { PROC_UNLOCK(p); oldvp = NULL; sx_xlock(&proctree_lock); if (vp == p->p_session->s_ttyvp) { SESS_LOCK(p->p_session); mtx_lock(&devfs_de_interlock); VI_LOCK(vp); if (devfs_usecountl(vp) == 2 && !VN_IS_DOOMED(vp)) { p->p_session->s_ttyvp = NULL; p->p_session->s_ttydp = NULL; oldvp = vp; } VI_UNLOCK(vp); mtx_unlock(&devfs_de_interlock); SESS_UNLOCK(p->p_session); } sx_xunlock(&proctree_lock); if (oldvp != NULL) devfs_ctty_unref(oldvp); } else PROC_UNLOCK(p); } /* * We do not want to really close the device if it * is still in use unless we are trying to close it * forcibly. Since every use (buffer, vnode, swap, cmap) * holds a reference to the vnode, and because we mark * any other vnodes that alias this device, when the * sum of the reference counts on all the aliased * vnodes descends to one, we are on last close. */ dsw = dev_refthread(dev, &ref); if (dsw == NULL) return (ENXIO); dflags = 0; mtx_lock(&devfs_de_interlock); VI_LOCK(vp); if (devfs_usecountl(vp) == 1) dflags |= FLASTCLOSE; devfs_usecount_subl(vp); mtx_unlock(&devfs_de_interlock); if (VN_IS_DOOMED(vp)) { /* Forced close. */ dflags |= FREVOKE | FNONBLOCK; } else if (dsw->d_flags & D_TRACKCLOSE) { /* Keep device updated on status. */ } else if ((dflags & FLASTCLOSE) == 0) { VI_UNLOCK(vp); dev_relthread(dev, ref); return (0); } vholdnz(vp); VI_UNLOCK(vp); vp_locked = VOP_ISLOCKED(vp); VOP_UNLOCK(vp); KASSERT(dev->si_refcount > 0, ("devfs_close() on un-referenced struct cdev *(%s)", devtoname(dev))); error = dsw->d_close(dev, ap->a_fflag | dflags, S_IFCHR, td); dev_relthread(dev, ref); vn_lock(vp, vp_locked | LK_RETRY); vdrop(vp); return (error); } static int devfs_close_f(struct file *fp, struct thread *td) { int error; struct file *fpop; /* * NB: td may be NULL if this descriptor is closed due to * garbage collection from a closed UNIX domain socket. */ fpop = curthread->td_fpop; curthread->td_fpop = fp; error = vnops.fo_close(fp, td); curthread->td_fpop = fpop; /* * The f_cdevpriv cannot be assigned non-NULL value while we * are destroying the file. */ if (fp->f_cdevpriv != NULL) devfs_fpdrop(fp); return (error); } static int devfs_getattr(struct vop_getattr_args *ap) { struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; struct devfs_dirent *de; struct devfs_mount *dmp; struct cdev *dev; struct timeval boottime; int error; error = devfs_populate_vp(vp); if (error != 0) return (error); dmp = VFSTODEVFS(vp->v_mount); sx_xunlock(&dmp->dm_lock); de = vp->v_data; KASSERT(de != NULL, ("Null dirent in devfs_getattr vp=%p", vp)); if (vp->v_type == VDIR) { de = de->de_dir; KASSERT(de != NULL, ("Null dir dirent in devfs_getattr vp=%p", vp)); } vap->va_uid = de->de_uid; vap->va_gid = de->de_gid; vap->va_mode = de->de_mode; if (vp->v_type == VLNK) vap->va_size = strlen(de->de_symlink); else if (vp->v_type == VDIR) vap->va_size = vap->va_bytes = DEV_BSIZE; else vap->va_size = 0; if (vp->v_type != VDIR) vap->va_bytes = 0; vap->va_blocksize = DEV_BSIZE; vap->va_type = vp->v_type; getboottime(&boottime); #define fix(aa) \ do { \ if ((aa).tv_sec <= 3600) { \ (aa).tv_sec = boottime.tv_sec; \ (aa).tv_nsec = boottime.tv_usec * 1000; \ } \ } while (0) if (vp->v_type != VCHR) { fix(de->de_atime); vap->va_atime = de->de_atime; fix(de->de_mtime); vap->va_mtime = de->de_mtime; fix(de->de_ctime); vap->va_ctime = de->de_ctime; } else { dev = vp->v_rdev; fix(dev->si_atime); vap->va_atime = dev->si_atime; fix(dev->si_mtime); vap->va_mtime = dev->si_mtime; fix(dev->si_ctime); vap->va_ctime = dev->si_ctime; vap->va_rdev = cdev2priv(dev)->cdp_inode; } vap->va_gen = 0; vap->va_flags = 0; vap->va_filerev = 0; vap->va_nlink = de->de_links; vap->va_fileid = de->de_inode; return (error); } /* ARGSUSED */ static int devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struct thread *td) { struct file *fpop; int error; fpop = td->td_fpop; td->td_fpop = fp; error = vnops.fo_ioctl(fp, com, data, cred, td); td->td_fpop = fpop; return (error); } void * fiodgname_buf_get_ptr(void *fgnp, u_long com) { union { struct fiodgname_arg fgn; #ifdef COMPAT_FREEBSD32 struct fiodgname_arg32 fgn32; #endif } *fgnup; fgnup = fgnp; switch (com) { case FIODGNAME: return (fgnup->fgn.buf); #ifdef COMPAT_FREEBSD32 case FIODGNAME_32: return ((void *)(uintptr_t)fgnup->fgn32.buf); #endif default: panic("Unhandled ioctl command %ld", com); } } static int devfs_ioctl(struct vop_ioctl_args *ap) { struct fiodgname_arg *fgn; struct vnode *vpold, *vp; struct cdevsw *dsw; struct thread *td; struct session *sess; struct cdev *dev; int error, ref, i; const char *p; u_long com; vp = ap->a_vp; com = ap->a_command; td = ap->a_td; dsw = devvn_refthread(vp, &dev, &ref); if (dsw == NULL) return (ENXIO); KASSERT(dev->si_refcount > 0, ("devfs: un-referenced struct cdev *(%s)", devtoname(dev))); switch (com) { case FIODTYPE: *(int *)ap->a_data = dsw->d_flags & D_TYPEMASK; error = 0; break; case FIODGNAME: #ifdef COMPAT_FREEBSD32 case FIODGNAME_32: #endif fgn = ap->a_data; p = devtoname(dev); i = strlen(p) + 1; if (i > fgn->len) error = EINVAL; else error = copyout(p, fiodgname_buf_get_ptr(fgn, com), i); break; default: error = dsw->d_ioctl(dev, com, ap->a_data, ap->a_fflag, td); } dev_relthread(dev, ref); if (error == ENOIOCTL) error = ENOTTY; if (error == 0 && com == TIOCSCTTY) { /* * Do nothing if reassigning same control tty, or if the * control tty has already disappeared. If it disappeared, * it's because we were racing with TIOCNOTTY. TIOCNOTTY * already took care of releasing the old vnode and we have * nothing left to do. */ sx_slock(&proctree_lock); sess = td->td_proc->p_session; if (sess->s_ttyvp == vp || sess->s_ttyp == NULL) { sx_sunlock(&proctree_lock); return (0); } devfs_ctty_ref(vp); SESS_LOCK(sess); vpold = sess->s_ttyvp; sess->s_ttyvp = vp; sess->s_ttydp = cdev2priv(dev); SESS_UNLOCK(sess); sx_sunlock(&proctree_lock); /* Get rid of reference to old control tty */ if (vpold) devfs_ctty_unref(vpold); } return (error); } /* ARGSUSED */ static int devfs_kqfilter_f(struct file *fp, struct knote *kn) { struct cdev *dev; struct cdevsw *dsw; int error, ref; struct file *fpop; struct thread *td; td = curthread; fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw, &ref); if (error) return (error); error = dsw->d_kqfilter(dev, kn); td->td_fpop = fpop; dev_relthread(dev, ref); return (error); } static inline int devfs_prison_check(struct devfs_dirent *de, struct thread *td) { struct cdev_priv *cdp; struct ucred *dcr; struct proc *p; int error; cdp = de->de_cdp; if (cdp == NULL) return (0); dcr = cdp->cdp_c.si_cred; if (dcr == NULL) return (0); error = prison_check(td->td_ucred, dcr); if (error == 0) return (0); /* We do, however, allow access to the controlling terminal */ p = td->td_proc; PROC_LOCK(p); if (!(p->p_flag & P_CONTROLT)) { PROC_UNLOCK(p); return (error); } if (p->p_session->s_ttydp == cdp) error = 0; PROC_UNLOCK(p); return (error); } static int devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock) { struct componentname *cnp; struct vnode *dvp, **vpp; struct thread *td; struct devfs_dirent *de, *dd; struct devfs_dirent **dde; struct devfs_mount *dmp; struct mount *mp; struct cdev *cdev; int error, flags, nameiop, dvplocked; char specname[SPECNAMELEN + 1], *pname; td = curthread; cnp = ap->a_cnp; vpp = ap->a_vpp; dvp = ap->a_dvp; pname = cnp->cn_nameptr; flags = cnp->cn_flags; nameiop = cnp->cn_nameiop; mp = dvp->v_mount; dmp = VFSTODEVFS(mp); dd = dvp->v_data; *vpp = NULL; if ((flags & ISLASTCN) && nameiop == RENAME) return (EOPNOTSUPP); if (dvp->v_type != VDIR) return (ENOTDIR); if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) return (EIO); error = vn_dir_check_exec(dvp, cnp); if (error != 0) return (error); if (cnp->cn_namelen == 1 && *pname == '.') { if ((flags & ISLASTCN) && nameiop != LOOKUP) return (EINVAL); *vpp = dvp; - VREF(dvp); + vref(dvp); return (0); } if (flags & ISDOTDOT) { if ((flags & ISLASTCN) && nameiop != LOOKUP) return (EINVAL); de = devfs_parent_dirent(dd); if (de == NULL) return (ENOENT); dvplocked = VOP_ISLOCKED(dvp); VOP_UNLOCK(dvp); error = devfs_allocv(de, mp, cnp->cn_lkflags & LK_TYPE_MASK, vpp); *dm_unlock = 0; vn_lock(dvp, dvplocked | LK_RETRY); return (error); } dd = dvp->v_data; de = devfs_find(dd, cnp->cn_nameptr, cnp->cn_namelen, 0); while (de == NULL) { /* While(...) so we can use break */ if (nameiop == DELETE) return (ENOENT); /* * OK, we didn't have an entry for the name we were asked for * so we try to see if anybody can create it on demand. */ pname = devfs_fqpn(specname, dmp, dd, cnp); if (pname == NULL) break; cdev = NULL; DEVFS_DMP_HOLD(dmp); sx_xunlock(&dmp->dm_lock); EVENTHANDLER_INVOKE(dev_clone, td->td_ucred, pname, strlen(pname), &cdev); if (cdev == NULL) sx_xlock(&dmp->dm_lock); else if (devfs_populate_vp(dvp) != 0) { *dm_unlock = 0; sx_xlock(&dmp->dm_lock); if (DEVFS_DMP_DROP(dmp)) { sx_xunlock(&dmp->dm_lock); devfs_unmount_final(dmp); } else sx_xunlock(&dmp->dm_lock); dev_rel(cdev); return (ENOENT); } if (DEVFS_DMP_DROP(dmp)) { *dm_unlock = 0; sx_xunlock(&dmp->dm_lock); devfs_unmount_final(dmp); if (cdev != NULL) dev_rel(cdev); return (ENOENT); } if (cdev == NULL) break; dev_lock(); dde = &cdev2priv(cdev)->cdp_dirents[dmp->dm_idx]; if (dde != NULL && *dde != NULL) de = *dde; dev_unlock(); dev_rel(cdev); break; } if (de == NULL || de->de_flags & DE_WHITEOUT) { if ((nameiop == CREATE || nameiop == RENAME) && (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { return (EJUSTRETURN); } return (ENOENT); } if (devfs_prison_check(de, td)) return (ENOENT); if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); if (error) return (error); if (*vpp == dvp) { - VREF(dvp); + vref(dvp); *vpp = dvp; return (0); } } error = devfs_allocv(de, mp, cnp->cn_lkflags & LK_TYPE_MASK, vpp); *dm_unlock = 0; return (error); } static int devfs_lookup(struct vop_lookup_args *ap) { int j; struct devfs_mount *dmp; int dm_unlock; if (devfs_populate_vp(ap->a_dvp) != 0) return (ENOTDIR); dmp = VFSTODEVFS(ap->a_dvp->v_mount); dm_unlock = 1; j = devfs_lookupx(ap, &dm_unlock); if (dm_unlock == 1) sx_xunlock(&dmp->dm_lock); return (j); } static int devfs_mknod(struct vop_mknod_args *ap) { struct componentname *cnp; struct vnode *dvp, **vpp; struct devfs_dirent *dd, *de; struct devfs_mount *dmp; int error; /* * The only type of node we should be creating here is a * character device, for anything else return EOPNOTSUPP. */ if (ap->a_vap->va_type != VCHR) return (EOPNOTSUPP); dvp = ap->a_dvp; dmp = VFSTODEVFS(dvp->v_mount); cnp = ap->a_cnp; vpp = ap->a_vpp; dd = dvp->v_data; error = ENOENT; sx_xlock(&dmp->dm_lock); TAILQ_FOREACH(de, &dd->de_dlist, de_list) { if (cnp->cn_namelen != de->de_dirent->d_namlen) continue; if (de->de_dirent->d_type == DT_CHR && (de->de_cdp->cdp_flags & CDP_ACTIVE) == 0) continue; if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, de->de_dirent->d_namlen) != 0) continue; if (de->de_flags & DE_WHITEOUT) break; goto notfound; } if (de == NULL) goto notfound; de->de_flags &= ~DE_WHITEOUT; error = devfs_allocv(de, dvp->v_mount, LK_EXCLUSIVE, vpp); return (error); notfound: sx_xunlock(&dmp->dm_lock); return (error); } /* ARGSUSED */ static int devfs_open(struct vop_open_args *ap) { struct thread *td = ap->a_td; struct vnode *vp = ap->a_vp; struct cdev *dev = vp->v_rdev; struct file *fp = ap->a_fp; int error, ref, vlocked; struct cdevsw *dsw; struct file *fpop; if (vp->v_type == VBLK) return (ENXIO); if (dev == NULL) return (ENXIO); /* Make this field valid before any I/O in d_open. */ if (dev->si_iosize_max == 0) dev->si_iosize_max = DFLTPHYS; dsw = dev_refthread(dev, &ref); if (dsw == NULL) return (ENXIO); if (fp == NULL && dsw->d_fdopen != NULL) { dev_relthread(dev, ref); return (ENXIO); } if (vp->v_type == VCHR) devfs_usecount_add(vp); vlocked = VOP_ISLOCKED(vp); VOP_UNLOCK(vp); fpop = td->td_fpop; td->td_fpop = fp; if (fp != NULL) { fp->f_data = dev; fp->f_vnode = vp; } if (dsw->d_fdopen != NULL) error = dsw->d_fdopen(dev, ap->a_mode, td, fp); else error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td); /* Clean up any cdevpriv upon error. */ if (error != 0) devfs_clear_cdevpriv(); td->td_fpop = fpop; vn_lock(vp, vlocked | LK_RETRY); if (error != 0 && vp->v_type == VCHR) devfs_usecount_sub(vp); dev_relthread(dev, ref); if (error != 0) { if (error == ERESTART) error = EINTR; return (error); } #if 0 /* /dev/console */ KASSERT(fp != NULL, ("Could not vnode bypass device on NULL fp")); #else if (fp == NULL) return (error); #endif if (fp->f_ops == &badfileops) finit(fp, fp->f_flag, DTYPE_VNODE, dev, &devfs_ops_f); return (error); } static int devfs_pathconf(struct vop_pathconf_args *ap) { switch (ap->a_name) { case _PC_FILESIZEBITS: *ap->a_retval = 64; return (0); case _PC_NAME_MAX: *ap->a_retval = NAME_MAX; return (0); case _PC_LINK_MAX: *ap->a_retval = INT_MAX; return (0); case _PC_SYMLINK_MAX: *ap->a_retval = MAXPATHLEN; return (0); case _PC_MAX_CANON: if (ap->a_vp->v_vflag & VV_ISTTY) { *ap->a_retval = MAX_CANON; return (0); } return (EINVAL); case _PC_MAX_INPUT: if (ap->a_vp->v_vflag & VV_ISTTY) { *ap->a_retval = MAX_INPUT; return (0); } return (EINVAL); case _PC_VDISABLE: if (ap->a_vp->v_vflag & VV_ISTTY) { *ap->a_retval = _POSIX_VDISABLE; return (0); } return (EINVAL); case _PC_MAC_PRESENT: #ifdef MAC /* * If MAC is enabled, devfs automatically supports * trivial non-persistent label storage. */ *ap->a_retval = 1; #else *ap->a_retval = 0; #endif return (0); case _PC_CHOWN_RESTRICTED: *ap->a_retval = 1; return (0); default: return (vop_stdpathconf(ap)); } /* NOTREACHED */ } /* ARGSUSED */ static int devfs_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td) { struct cdev *dev; struct cdevsw *dsw; int error, ref; struct file *fpop; fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw, &ref); if (error != 0) { error = vnops.fo_poll(fp, events, cred, td); return (error); } error = dsw->d_poll(dev, events, td); td->td_fpop = fpop; dev_relthread(dev, ref); return(error); } /* * Print out the contents of a special device vnode. */ static int devfs_print(struct vop_print_args *ap) { printf("\tdev %s\n", devtoname(ap->a_vp->v_rdev)); return (0); } static int devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td) { struct cdev *dev; int ioflag, error, ref; ssize_t resid; struct cdevsw *dsw; struct file *fpop; if (uio->uio_resid > DEVFS_IOSIZE_MAX) return (EINVAL); fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw, &ref); if (error != 0) { error = vnops.fo_read(fp, uio, cred, flags, td); return (error); } resid = uio->uio_resid; ioflag = fp->f_flag & (O_NONBLOCK | O_DIRECT); if (ioflag & O_DIRECT) ioflag |= IO_DIRECT; foffset_lock_uio(fp, uio, flags | FOF_NOLOCK); error = dsw->d_read(dev, uio, ioflag); if (uio->uio_resid != resid || (error == 0 && resid != 0)) devfs_timestamp(&dev->si_atime); td->td_fpop = fpop; dev_relthread(dev, ref); foffset_unlock_uio(fp, uio, flags | FOF_NOLOCK | FOF_NEXTOFF_R); return (error); } static int devfs_readdir(struct vop_readdir_args *ap) { int error; struct uio *uio; struct dirent *dp; struct devfs_dirent *dd; struct devfs_dirent *de; struct devfs_mount *dmp; off_t off; int *tmp_ncookies = NULL; ssize_t startresid; if (ap->a_vp->v_type != VDIR) return (ENOTDIR); uio = ap->a_uio; if (uio->uio_offset < 0) return (EINVAL); /* * XXX: This is a temporary hack to get around this filesystem not * supporting cookies. We store the location of the ncookies pointer * in a temporary variable before calling vfs_subr.c:vfs_read_dirent() * and set the number of cookies to 0. We then set the pointer to * NULL so that vfs_read_dirent doesn't try to call realloc() on * ap->a_cookies. Later in this function, we restore the ap->a_ncookies * pointer to its original location before returning to the caller. */ if (ap->a_ncookies != NULL) { tmp_ncookies = ap->a_ncookies; *ap->a_ncookies = 0; ap->a_ncookies = NULL; } dmp = VFSTODEVFS(ap->a_vp->v_mount); if (devfs_populate_vp(ap->a_vp) != 0) { if (tmp_ncookies != NULL) ap->a_ncookies = tmp_ncookies; return (EIO); } error = 0; de = ap->a_vp->v_data; off = 0; startresid = uio->uio_resid; TAILQ_FOREACH(dd, &de->de_dlist, de_list) { KASSERT(dd->de_cdp != (void *)0xdeadc0de, ("%s %d\n", __func__, __LINE__)); if (dd->de_flags & (DE_COVERED | DE_WHITEOUT)) continue; if (devfs_prison_check(dd, uio->uio_td)) continue; if (dd->de_dirent->d_type == DT_DIR) de = dd->de_dir; else de = dd; dp = dd->de_dirent; MPASS(dp->d_reclen == GENERIC_DIRSIZ(dp)); if (dp->d_reclen > uio->uio_resid) { /* Nothing was copied out, return EINVAL. */ if (uio->uio_resid == startresid) error = EINVAL; /* Otherwise stop. */ break; } dp->d_fileno = de->de_inode; /* NOTE: d_off is the offset for the *next* entry. */ dp->d_off = off + dp->d_reclen; if (off >= uio->uio_offset) { error = vfs_read_dirent(ap, dp, off); if (error) break; } off += dp->d_reclen; } sx_xunlock(&dmp->dm_lock); uio->uio_offset = off; /* * Restore ap->a_ncookies if it wasn't originally NULL in the first * place. */ if (tmp_ncookies != NULL) ap->a_ncookies = tmp_ncookies; if (dd == NULL && error == 0 && ap->a_eofflag != NULL) *ap->a_eofflag = 1; return (error); } static int devfs_readlink(struct vop_readlink_args *ap) { struct devfs_dirent *de; de = ap->a_vp->v_data; return (uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio)); } static void devfs_reclaiml(struct vnode *vp) { struct devfs_dirent *de; mtx_assert(&devfs_de_interlock, MA_OWNED); de = vp->v_data; if (de != NULL) { MPASS(de->de_usecount == 0); de->de_vnode = NULL; vp->v_data = NULL; } } static int devfs_reclaim(struct vop_reclaim_args *ap) { struct vnode *vp; vp = ap->a_vp; mtx_lock(&devfs_de_interlock); devfs_reclaiml(vp); mtx_unlock(&devfs_de_interlock); return (0); } static int devfs_reclaim_vchr(struct vop_reclaim_args *ap) { struct vnode *vp; struct cdev *dev; vp = ap->a_vp; MPASS(vp->v_type == VCHR); mtx_lock(&devfs_de_interlock); VI_LOCK(vp); devfs_usecount_subl(vp); devfs_reclaiml(vp); mtx_unlock(&devfs_de_interlock); dev_lock(); dev = vp->v_rdev; vp->v_rdev = NULL; dev_unlock(); VI_UNLOCK(vp); if (dev != NULL) dev_rel(dev); return (0); } static int devfs_remove(struct vop_remove_args *ap) { struct vnode *dvp = ap->a_dvp; struct vnode *vp = ap->a_vp; struct devfs_dirent *dd; struct devfs_dirent *de, *de_covered; struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); ASSERT_VOP_ELOCKED(dvp, "devfs_remove"); ASSERT_VOP_ELOCKED(vp, "devfs_remove"); sx_xlock(&dmp->dm_lock); dd = ap->a_dvp->v_data; de = vp->v_data; if (de->de_cdp == NULL) { TAILQ_REMOVE(&dd->de_dlist, de, de_list); if (de->de_dirent->d_type == DT_LNK) { de_covered = devfs_find(dd, de->de_dirent->d_name, de->de_dirent->d_namlen, 0); if (de_covered != NULL) de_covered->de_flags &= ~DE_COVERED; } /* We need to unlock dvp because devfs_delete() may lock it. */ VOP_UNLOCK(vp); if (dvp != vp) VOP_UNLOCK(dvp); devfs_delete(dmp, de, 0); sx_xunlock(&dmp->dm_lock); if (dvp != vp) vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); } else { de->de_flags |= DE_WHITEOUT; sx_xunlock(&dmp->dm_lock); } return (0); } /* * Revoke is called on a tty when a terminal session ends. The vnode * is orphaned by setting v_op to deadfs so we need to let go of it * as well so that we create a new one next time around. * */ static int devfs_revoke(struct vop_revoke_args *ap) { struct vnode *vp = ap->a_vp, *vp2; struct cdev *dev; struct cdev_priv *cdp; struct devfs_dirent *de; enum vgetstate vs; u_int i; KASSERT((ap->a_flags & REVOKEALL) != 0, ("devfs_revoke !REVOKEALL")); dev = vp->v_rdev; cdp = cdev2priv(dev); dev_lock(); cdp->cdp_inuse++; dev_unlock(); vhold(vp); vgone(vp); vdrop(vp); VOP_UNLOCK(vp); loop: for (;;) { mtx_lock(&devfs_de_interlock); dev_lock(); vp2 = NULL; for (i = 0; i <= cdp->cdp_maxdirent; i++) { de = cdp->cdp_dirents[i]; if (de == NULL) continue; vp2 = de->de_vnode; if (vp2 != NULL) { dev_unlock(); vs = vget_prep(vp2); mtx_unlock(&devfs_de_interlock); if (vget_finish(vp2, LK_EXCLUSIVE, vs) != 0) goto loop; vhold(vp2); vgone(vp2); vdrop(vp2); vput(vp2); break; } } if (vp2 != NULL) { continue; } dev_unlock(); mtx_unlock(&devfs_de_interlock); break; } dev_lock(); cdp->cdp_inuse--; if (!(cdp->cdp_flags & CDP_ACTIVE) && cdp->cdp_inuse == 0) { KASSERT((cdp->cdp_flags & CDP_ON_ACTIVE_LIST) != 0, ("%s: cdp %p (%s) not on active list", __func__, cdp, dev->si_name)); cdp->cdp_flags &= ~CDP_ON_ACTIVE_LIST; TAILQ_REMOVE(&cdevp_list, cdp, cdp_list); dev_unlock(); dev_rel(&cdp->cdp_c); } else dev_unlock(); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); return (0); } static int devfs_rioctl(struct vop_ioctl_args *ap) { struct vnode *vp; struct devfs_mount *dmp; int error; vp = ap->a_vp; vn_lock(vp, LK_SHARED | LK_RETRY); if (VN_IS_DOOMED(vp)) { VOP_UNLOCK(vp); return (EBADF); } dmp = VFSTODEVFS(vp->v_mount); sx_xlock(&dmp->dm_lock); VOP_UNLOCK(vp); DEVFS_DMP_HOLD(dmp); devfs_populate(dmp); if (DEVFS_DMP_DROP(dmp)) { sx_xunlock(&dmp->dm_lock); devfs_unmount_final(dmp); return (ENOENT); } error = devfs_rules_ioctl(dmp, ap->a_command, ap->a_data, ap->a_td); sx_xunlock(&dmp->dm_lock); return (error); } static int devfs_rread(struct vop_read_args *ap) { if (ap->a_vp->v_type != VDIR) return (EINVAL); return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); } static int devfs_setattr(struct vop_setattr_args *ap) { struct devfs_dirent *de; struct vattr *vap; struct vnode *vp; struct thread *td; int c, error; uid_t uid; gid_t gid; vap = ap->a_vap; vp = ap->a_vp; td = curthread; if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || (vap->va_blocksize != VNOVAL) || (vap->va_flags != VNOVAL && vap->va_flags != 0) || (vap->va_rdev != VNOVAL) || ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { return (EINVAL); } error = devfs_populate_vp(vp); if (error != 0) return (error); de = vp->v_data; if (vp->v_type == VDIR) de = de->de_dir; c = 0; if (vap->va_uid == (uid_t)VNOVAL) uid = de->de_uid; else uid = vap->va_uid; if (vap->va_gid == (gid_t)VNOVAL) gid = de->de_gid; else gid = vap->va_gid; if (uid != de->de_uid || gid != de->de_gid) { if ((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || (gid != de->de_gid && !groupmember(gid, ap->a_cred))) { error = priv_check(td, PRIV_VFS_CHOWN); if (error != 0) goto ret; } de->de_uid = uid; de->de_gid = gid; c = 1; } if (vap->va_mode != (mode_t)VNOVAL) { if (ap->a_cred->cr_uid != de->de_uid) { error = priv_check(td, PRIV_VFS_ADMIN); if (error != 0) goto ret; } de->de_mode = vap->va_mode; c = 1; } if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { error = vn_utimes_perm(vp, vap, ap->a_cred, td); if (error != 0) goto ret; if (vap->va_atime.tv_sec != VNOVAL) { if (vp->v_type == VCHR) vp->v_rdev->si_atime = vap->va_atime; else de->de_atime = vap->va_atime; } if (vap->va_mtime.tv_sec != VNOVAL) { if (vp->v_type == VCHR) vp->v_rdev->si_mtime = vap->va_mtime; else de->de_mtime = vap->va_mtime; } c = 1; } if (c) { if (vp->v_type == VCHR) vfs_timestamp(&vp->v_rdev->si_ctime); else vfs_timestamp(&de->de_mtime); } ret: sx_xunlock(&VFSTODEVFS(vp->v_mount)->dm_lock); return (error); } #ifdef MAC static int devfs_setlabel(struct vop_setlabel_args *ap) { struct vnode *vp; struct devfs_dirent *de; vp = ap->a_vp; de = vp->v_data; mac_vnode_relabel(ap->a_cred, vp, ap->a_label); mac_devfs_update(vp->v_mount, de, vp); return (0); } #endif static int devfs_stat_f(struct file *fp, struct stat *sb, struct ucred *cred) { return (vnops.fo_stat(fp, sb, cred)); } static int devfs_symlink(struct vop_symlink_args *ap) { int i, error; struct devfs_dirent *dd; struct devfs_dirent *de, *de_covered, *de_dotdot; struct devfs_mount *dmp; error = priv_check(curthread, PRIV_DEVFS_SYMLINK); if (error) return(error); dmp = VFSTODEVFS(ap->a_dvp->v_mount); if (devfs_populate_vp(ap->a_dvp) != 0) return (ENOENT); dd = ap->a_dvp->v_data; de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); de->de_flags = DE_USER; de->de_uid = 0; de->de_gid = 0; de->de_mode = 0755; de->de_inode = alloc_unr(devfs_inos); de->de_dir = dd; de->de_dirent->d_type = DT_LNK; i = strlen(ap->a_target) + 1; de->de_symlink = malloc(i, M_DEVFS, M_WAITOK); bcopy(ap->a_target, de->de_symlink, i); #ifdef MAC mac_devfs_create_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); #endif de_covered = devfs_find(dd, de->de_dirent->d_name, de->de_dirent->d_namlen, 0); if (de_covered != NULL) { if ((de_covered->de_flags & DE_USER) != 0) { devfs_delete(dmp, de, DEVFS_DEL_NORECURSE); sx_xunlock(&dmp->dm_lock); return (EEXIST); } KASSERT((de_covered->de_flags & DE_COVERED) == 0, ("devfs_symlink: entry %p already covered", de_covered)); de_covered->de_flags |= DE_COVERED; } de_dotdot = TAILQ_FIRST(&dd->de_dlist); /* "." */ de_dotdot = TAILQ_NEXT(de_dotdot, de_list); /* ".." */ TAILQ_INSERT_AFTER(&dd->de_dlist, de_dotdot, de, de_list); devfs_dir_ref_de(dmp, dd); devfs_rules_apply(dmp, de); return (devfs_allocv(de, ap->a_dvp->v_mount, LK_EXCLUSIVE, ap->a_vpp)); } static int devfs_truncate_f(struct file *fp, off_t length, struct ucred *cred, struct thread *td) { return (vnops.fo_truncate(fp, length, cred, td)); } static int devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td) { struct cdev *dev; int error, ioflag, ref; ssize_t resid; struct cdevsw *dsw; struct file *fpop; if (uio->uio_resid > DEVFS_IOSIZE_MAX) return (EINVAL); fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw, &ref); if (error != 0) { error = vnops.fo_write(fp, uio, cred, flags, td); return (error); } KASSERT(uio->uio_td == td, ("uio_td %p is not td %p", uio->uio_td, td)); ioflag = fp->f_flag & (O_NONBLOCK | O_DIRECT | O_FSYNC); if (ioflag & O_DIRECT) ioflag |= IO_DIRECT; foffset_lock_uio(fp, uio, flags | FOF_NOLOCK); resid = uio->uio_resid; error = dsw->d_write(dev, uio, ioflag); if (uio->uio_resid != resid || (error == 0 && resid != 0)) { devfs_timestamp(&dev->si_ctime); dev->si_mtime = dev->si_ctime; } td->td_fpop = fpop; dev_relthread(dev, ref); foffset_unlock_uio(fp, uio, flags | FOF_NOLOCK | FOF_NEXTOFF_W); return (error); } static int devfs_mmap_f(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, vm_prot_t cap_maxprot, int flags, vm_ooffset_t foff, struct thread *td) { struct cdev *dev; struct cdevsw *dsw; struct mount *mp; struct vnode *vp; struct file *fpop; vm_object_t object; vm_prot_t maxprot; int error, ref; vp = fp->f_vnode; /* * Ensure that file and memory protections are * compatible. */ mp = vp->v_mount; if (mp != NULL && (mp->mnt_flag & MNT_NOEXEC) != 0) { maxprot = VM_PROT_NONE; if ((prot & VM_PROT_EXECUTE) != 0) return (EACCES); } else maxprot = VM_PROT_EXECUTE; if ((fp->f_flag & FREAD) != 0) maxprot |= VM_PROT_READ; else if ((prot & VM_PROT_READ) != 0) return (EACCES); /* * If we are sharing potential changes via MAP_SHARED and we * are trying to get write permission although we opened it * without asking for it, bail out. * * Note that most character devices always share mappings. * The one exception is that D_MMAP_ANON devices * (i.e. /dev/zero) permit private writable mappings. * * Rely on vm_mmap_cdev() to fail invalid MAP_PRIVATE requests * as well as updating maxprot to permit writing for * D_MMAP_ANON devices rather than doing that here. */ if ((flags & MAP_SHARED) != 0) { if ((fp->f_flag & FWRITE) != 0) maxprot |= VM_PROT_WRITE; else if ((prot & VM_PROT_WRITE) != 0) return (EACCES); } maxprot &= cap_maxprot; fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw, &ref); if (error != 0) return (error); error = vm_mmap_cdev(td, size, prot, &maxprot, &flags, dev, dsw, &foff, &object); td->td_fpop = fpop; dev_relthread(dev, ref); if (error != 0) return (error); error = vm_mmap_object(map, addr, size, prot, maxprot, flags, object, foff, FALSE, td); if (error != 0) vm_object_deallocate(object); return (error); } dev_t dev2udev(struct cdev *x) { if (x == NULL) return (NODEV); return (cdev2priv(x)->cdp_inode); } static int devfs_cmp_f(struct file *fp1, struct file *fp2, struct thread *td) { if (fp2->f_type != DTYPE_VNODE || fp2->f_ops != &devfs_ops_f) return (3); return (kcmp_cmp((uintptr_t)fp1->f_data, (uintptr_t)fp2->f_data)); } static const struct fileops devfs_ops_f = { .fo_read = devfs_read_f, .fo_write = devfs_write_f, .fo_truncate = devfs_truncate_f, .fo_ioctl = devfs_ioctl_f, .fo_poll = devfs_poll_f, .fo_kqfilter = devfs_kqfilter_f, .fo_stat = devfs_stat_f, .fo_close = devfs_close_f, .fo_chmod = vn_chmod, .fo_chown = vn_chown, .fo_sendfile = vn_sendfile, .fo_seek = vn_seek, .fo_fill_kinfo = vn_fill_kinfo, .fo_mmap = devfs_mmap_f, .fo_cmp = devfs_cmp_f, .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE }; /* Vops for non-CHR vnodes in /dev. */ static struct vop_vector devfs_vnodeops = { .vop_default = &default_vnodeops, .vop_access = devfs_access, .vop_getattr = devfs_getattr, .vop_ioctl = devfs_rioctl, .vop_lookup = devfs_lookup, .vop_mknod = devfs_mknod, .vop_pathconf = devfs_pathconf, .vop_read = devfs_rread, .vop_readdir = devfs_readdir, .vop_readlink = devfs_readlink, .vop_reclaim = devfs_reclaim, .vop_remove = devfs_remove, .vop_revoke = devfs_revoke, .vop_setattr = devfs_setattr, #ifdef MAC .vop_setlabel = devfs_setlabel, #endif .vop_symlink = devfs_symlink, .vop_vptocnp = devfs_vptocnp, .vop_lock1 = vop_lock, .vop_unlock = vop_unlock, .vop_islocked = vop_islocked, .vop_add_writecount = vop_stdadd_writecount_nomsync, }; VFS_VOP_VECTOR_REGISTER(devfs_vnodeops); /* Vops for VCHR vnodes in /dev. */ static struct vop_vector devfs_specops = { .vop_default = &default_vnodeops, .vop_access = devfs_access, .vop_bmap = VOP_PANIC, .vop_close = devfs_close, .vop_create = VOP_PANIC, .vop_fsync = vop_stdfsync, .vop_getattr = devfs_getattr, .vop_ioctl = devfs_ioctl, .vop_link = VOP_PANIC, .vop_mkdir = VOP_PANIC, .vop_mknod = VOP_PANIC, .vop_open = devfs_open, .vop_pathconf = devfs_pathconf, .vop_poll = dead_poll, .vop_print = devfs_print, .vop_read = dead_read, .vop_readdir = VOP_PANIC, .vop_readlink = VOP_PANIC, .vop_reallocblks = VOP_PANIC, .vop_reclaim = devfs_reclaim_vchr, .vop_remove = devfs_remove, .vop_rename = VOP_PANIC, .vop_revoke = devfs_revoke, .vop_rmdir = VOP_PANIC, .vop_setattr = devfs_setattr, #ifdef MAC .vop_setlabel = devfs_setlabel, #endif .vop_strategy = VOP_PANIC, .vop_symlink = VOP_PANIC, .vop_vptocnp = devfs_vptocnp, .vop_write = dead_write, .vop_lock1 = vop_lock, .vop_unlock = vop_unlock, .vop_islocked = vop_islocked, .vop_add_writecount = vop_stdadd_writecount_nomsync, }; VFS_VOP_VECTOR_REGISTER(devfs_specops); /* * Our calling convention to the device drivers used to be that we passed * vnode.h IO_* flags to read()/write(), but we're moving to fcntl.h O_ * flags instead since that's what open(), close() and ioctl() takes and * we don't really want vnode.h in device drivers. * We solved the source compatibility by redefining some vnode flags to * be the same as the fcntl ones and by sending down the bitwise OR of * the respective fcntl/vnode flags. These CTASSERTS make sure nobody * pulls the rug out under this. */ CTASSERT(O_NONBLOCK == IO_NDELAY); CTASSERT(O_FSYNC == IO_SYNC); diff --git a/sys/fs/ext2fs/ext2_lookup.c b/sys/fs/ext2fs/ext2_lookup.c index c80e0f99ab56..bb830d07b126 100644 --- a/sys/fs/ext2fs/ext2_lookup.c +++ b/sys/fs/ext2fs/ext2_lookup.c @@ -1,1264 +1,1264 @@ /*- * modified for Lites 1.1 * * Aug 1995, Godmar Back (gback@cs.utah.edu) * University of Utah, Department of Computer Science */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SDT_PROVIDER_DECLARE(ext2fs); /* * ext2fs trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ SDT_PROBE_DEFINE2(ext2fs, , lookup, trace, "int", "char*"); SDT_PROBE_DEFINE4(ext2fs, , trace, ext2_dirbad_error, "char*", "ino_t", "doff_t", "char*"); SDT_PROBE_DEFINE5(ext2fs, , trace, ext2_dirbadentry_error, "char*", "int", "uint32_t", "uint16_t", "uint8_t"); static SYSCTL_NODE(_vfs, OID_AUTO, e2fs, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "EXT2FS filesystem"); /* DIRBLKSIZE in ffs is DEV_BSIZE (in most cases 512) while it is the native blocksize in ext2fs - thus, a #define is no longer appropriate */ #undef DIRBLKSIZ static u_char ext2_ft_to_dt[] = { DT_UNKNOWN, /* EXT2_FT_UNKNOWN */ DT_REG, /* EXT2_FT_REG_FILE */ DT_DIR, /* EXT2_FT_DIR */ DT_CHR, /* EXT2_FT_CHRDEV */ DT_BLK, /* EXT2_FT_BLKDEV */ DT_FIFO, /* EXT2_FT_FIFO */ DT_SOCK, /* EXT2_FT_SOCK */ DT_LNK, /* EXT2_FT_SYMLINK */ }; #define FTTODT(ft) \ ((ft) < nitems(ext2_ft_to_dt) ? ext2_ft_to_dt[(ft)] : DT_UNKNOWN) static u_char dt_to_ext2_ft[] = { EXT2_FT_UNKNOWN, /* DT_UNKNOWN */ EXT2_FT_FIFO, /* DT_FIFO */ EXT2_FT_CHRDEV, /* DT_CHR */ EXT2_FT_UNKNOWN, /* unused */ EXT2_FT_DIR, /* DT_DIR */ EXT2_FT_UNKNOWN, /* unused */ EXT2_FT_BLKDEV, /* DT_BLK */ EXT2_FT_UNKNOWN, /* unused */ EXT2_FT_REG_FILE, /* DT_REG */ EXT2_FT_UNKNOWN, /* unused */ EXT2_FT_SYMLINK, /* DT_LNK */ EXT2_FT_UNKNOWN, /* unused */ EXT2_FT_SOCK, /* DT_SOCK */ EXT2_FT_UNKNOWN, /* unused */ EXT2_FT_UNKNOWN, /* DT_WHT */ }; #define DTTOFT(dt) \ ((dt) < nitems(dt_to_ext2_ft) ? dt_to_ext2_ft[(dt)] : EXT2_FT_UNKNOWN) static int ext2_check_direntry(struct vnode *dp, struct ext2fs_direct_2 *de, int entryoffsetinblock); static int ext2_is_dot_entry(struct componentname *cnp); static int ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp, ino_t *dd_ino); static int ext2_is_dot_entry(struct componentname *cnp) { if (cnp->cn_namelen <= 2 && cnp->cn_nameptr[0] == '.' && (cnp->cn_nameptr[1] == '.' || cnp->cn_nameptr[1] == '\0')) return (1); return (0); } /* * Vnode op for reading directories. */ int ext2_readdir(struct vop_readdir_args *ap) { struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct buf *bp; struct inode *ip; struct ext2fs_direct_2 *dp, *edp; uint64_t *cookies; struct dirent dstdp; off_t offset, startoffset; size_t readcnt, skipcnt; ssize_t startresid; u_int ncookies; int DIRBLKSIZ = VTOI(ap->a_vp)->i_e2fs->e2fs_bsize; int error; if (uio->uio_offset < 0) return (EINVAL); ip = VTOI(vp); if (ap->a_ncookies != NULL) { if (uio->uio_resid < 0) ncookies = 0; else ncookies = uio->uio_resid; if (uio->uio_offset >= ip->i_size) ncookies = 0; else if (ip->i_size - uio->uio_offset < ncookies) ncookies = ip->i_size - uio->uio_offset; ncookies = ncookies / (offsetof(struct ext2fs_direct_2, e2d_namlen) + 4) + 1; cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK); *ap->a_ncookies = ncookies; *ap->a_cookies = cookies; } else { ncookies = 0; cookies = NULL; } offset = startoffset = uio->uio_offset; startresid = uio->uio_resid; error = 0; while (error == 0 && uio->uio_resid > 0 && uio->uio_offset < ip->i_size) { error = ext2_blkatoff(vp, uio->uio_offset, NULL, &bp); if (error) break; if (bp->b_offset + bp->b_bcount > ip->i_size) readcnt = ip->i_size - bp->b_offset; else readcnt = bp->b_bcount; skipcnt = (size_t)(uio->uio_offset - bp->b_offset) & ~(size_t)(DIRBLKSIZ - 1); offset = bp->b_offset + skipcnt; dp = (struct ext2fs_direct_2 *)&bp->b_data[skipcnt]; edp = (struct ext2fs_direct_2 *)&bp->b_data[readcnt]; while (error == 0 && uio->uio_resid > 0 && dp < edp) { if (le16toh(dp->e2d_reclen) <= offsetof(struct ext2fs_direct_2, e2d_namlen) || (caddr_t)dp + le16toh(dp->e2d_reclen) > (caddr_t)edp) { error = EIO; break; } /*- * "New" ext2fs directory entries differ in 3 ways * from ufs on-disk ones: * - the name is not necessarily NUL-terminated. * - the file type field always exists and always * follows the name length field. * - the file type is encoded in a different way. * * "Old" ext2fs directory entries need no special * conversions, since they are binary compatible * with "new" entries having a file type of 0 (i.e., * EXT2_FT_UNKNOWN). Splitting the old name length * field didn't make a mess like it did in ufs, * because ext2fs uses a machine-independent disk * layout. */ dstdp.d_namlen = dp->e2d_namlen; dstdp.d_type = FTTODT(dp->e2d_type); if (offsetof(struct ext2fs_direct_2, e2d_namlen) + dstdp.d_namlen > le16toh(dp->e2d_reclen)) { error = EIO; break; } if (offset < startoffset || le32toh(dp->e2d_ino) == 0) goto nextentry; dstdp.d_fileno = le32toh(dp->e2d_ino); dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp); bcopy(dp->e2d_name, dstdp.d_name, dstdp.d_namlen); /* NOTE: d_off is the offset of the *next* entry. */ dstdp.d_off = offset + le16toh(dp->e2d_reclen); dirent_terminate(&dstdp); if (dstdp.d_reclen > uio->uio_resid) { if (uio->uio_resid == startresid) error = EINVAL; else error = EJUSTRETURN; break; } /* Advance dp. */ error = uiomove((caddr_t)&dstdp, dstdp.d_reclen, uio); if (error) break; if (cookies != NULL) { KASSERT(ncookies > 0, ("ext2_readdir: cookies buffer too small")); *cookies = offset + le16toh(dp->e2d_reclen); cookies++; ncookies--; } nextentry: offset += le16toh(dp->e2d_reclen); dp = (struct ext2fs_direct_2 *)((caddr_t)dp + le16toh(dp->e2d_reclen)); } bqrelse(bp); uio->uio_offset = offset; } /* We need to correct uio_offset. */ uio->uio_offset = offset; if (error == EJUSTRETURN) error = 0; if (ap->a_ncookies != NULL) { if (error == 0) { *ap->a_ncookies -= ncookies; } else { free(*ap->a_cookies, M_TEMP); *ap->a_ncookies = 0; *ap->a_cookies = NULL; } } if (error == 0 && ap->a_eofflag) *ap->a_eofflag = ip->i_size <= uio->uio_offset; return (error); } /* * Convert a component of a pathname into a pointer to a locked inode. * This is a very central and rather complicated routine. * If the file system is not maintained in a strict tree hierarchy, * this can result in a deadlock situation (see comments in code below). * * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending * on whether the name is to be looked up, created, renamed, or deleted. * When CREATE, RENAME, or DELETE is specified, information usable in * creating, renaming, or deleting a directory entry may be calculated. * If flag has LOCKPARENT or'ed into it and the target of the pathname * exists, lookup returns both the target and its parent directory locked. * When creating or renaming and LOCKPARENT is specified, the target may * not be ".". When deleting and LOCKPARENT is specified, the target may * be "."., but the caller must check to ensure it does an vrele and vput * instead of two vputs. * * Overall outline of ext2_lookup: * * search for name in directory, to found or notfound * notfound: * if creating, return locked directory, leaving info on available slots * else return error * found: * if at end of path and deleting, return information to allow delete * if at end of path and rewriting (RENAME and LOCKPARENT), lock target * inode and return info to allow rewrite * if not at end, add name to cache; if at end and neither creating * nor deleting, add name to cache */ int ext2_lookup(struct vop_cachedlookup_args *ap) { return (ext2_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL)); } static int ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp, ino_t *dd_ino) { struct inode *dp; /* inode for directory being searched */ struct buf *bp; /* a buffer of directory entries */ struct ext2fs_direct_2 *ep; /* the current directory entry */ int entryoffsetinblock; /* offset of ep in bp's buffer */ struct ext2fs_searchslot ss; doff_t i_diroff; /* cached i_diroff value */ doff_t i_offset; /* cached i_offset value */ int numdirpasses; /* strategy for directory search */ doff_t endsearch; /* offset to end directory search */ doff_t prevoff; /* prev entry dp->i_offset */ struct vnode *pdp; /* saved dp during symlink work */ struct vnode *tdp; /* returned by VFS_VGET */ doff_t enduseful; /* pointer past last used dir slot */ u_long bmask; /* block offset mask */ int error; struct ucred *cred = cnp->cn_cred; int flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; ino_t ino, ino1; int ltype; int entry_found = 0; int DIRBLKSIZ = VTOI(vdp)->i_e2fs->e2fs_bsize; if (vpp != NULL) *vpp = NULL; dp = VTOI(vdp); bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; restart: bp = NULL; ss.slotoffset = -1; /* * We now have a segment name to search for, and a directory to search. * * Suppress search for slots unless creating * file and at end of pathname, in which case * we watch for a place to put the new file in * case it doesn't already exist. */ i_diroff = dp->i_diroff; ss.slotstatus = FOUND; ss.slotfreespace = ss.slotsize = ss.slotneeded = 0; if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) { ss.slotstatus = NONE; ss.slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen); /* * was ss.slotneeded = (sizeof(struct direct) - MAXNAMLEN + * cnp->cn_namelen + 3) &~ 3; */ } /* * Try to lookup dir entry using htree directory index. * * If we got an error or we want to find '.' or '..' entry, * we will fall back to linear search. */ if (!ext2_is_dot_entry(cnp) && ext2_htree_has_idx(dp)) { numdirpasses = 1; entryoffsetinblock = 0; switch (ext2_htree_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen, &bp, &entryoffsetinblock, &i_offset, &prevoff, &enduseful, &ss)) { case 0: ep = (struct ext2fs_direct_2 *)((char *)bp->b_data + (i_offset & bmask)); goto foundentry; case ENOENT: i_offset = roundup2(dp->i_size, DIRBLKSIZ); goto notfound; default: /* * Something failed; just fallback to do a linear * search. */ break; } } /* * If there is cached information on a previous search of * this directory, pick up where we last left off. * We cache only lookups as these are the most common * and have the greatest payoff. Caching CREATE has little * benefit as it usually must search the entire directory * to determine that the entry does not exist. Caching the * location of the last DELETE or RENAME has not reduced * profiling time and hence has been removed in the interest * of simplicity. */ if (nameiop != LOOKUP || i_diroff == 0 || i_diroff > dp->i_size) { entryoffsetinblock = 0; i_offset = 0; numdirpasses = 1; } else { i_offset = i_diroff; if ((entryoffsetinblock = i_offset & bmask) && (error = ext2_blkatoff(vdp, (off_t)i_offset, NULL, &bp))) return (error); numdirpasses = 2; nchstats.ncs_2passes++; } prevoff = i_offset; endsearch = roundup2(dp->i_size, DIRBLKSIZ); enduseful = 0; searchloop: while (i_offset < endsearch) { /* * If necessary, get the next directory block. */ if (bp != NULL) brelse(bp); error = ext2_blkatoff(vdp, (off_t)i_offset, NULL, &bp); if (error != 0) return (error); entryoffsetinblock = 0; if (ss.slotstatus == NONE) { ss.slotoffset = -1; ss.slotfreespace = 0; } error = ext2_search_dirblock(dp, bp->b_data, &entry_found, cnp->cn_nameptr, cnp->cn_namelen, &entryoffsetinblock, &i_offset, &prevoff, &enduseful, &ss); if (error != 0) { brelse(bp); return (error); } if (entry_found) { ep = (struct ext2fs_direct_2 *)((char *)bp->b_data + (entryoffsetinblock & bmask)); foundentry: ino = le32toh(ep->e2d_ino); goto found; } } notfound: /* * If we started in the middle of the directory and failed * to find our target, we must check the beginning as well. */ if (numdirpasses == 2) { numdirpasses--; i_offset = 0; endsearch = i_diroff; goto searchloop; } if (bp != NULL) brelse(bp); /* * If creating, and at end of pathname and current * directory has not been removed, then can consider * allowing file to be created. */ if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN) && dp->i_nlink != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. */ if ((error = VOP_ACCESS(vdp, VWRITE, cred, curthread)) != 0) return (error); /* * Return an indication of where the new directory * entry should be put. If we didn't find a slot, * then set dp->i_count to 0 indicating * that the new slot belongs at the end of the * directory. If we found a slot, then the new entry * can be put in the range from dp->i_offset to * dp->i_offset + dp->i_count. */ if (ss.slotstatus == NONE) { dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ); dp->i_count = 0; enduseful = dp->i_offset; } else { dp->i_offset = ss.slotoffset; dp->i_count = ss.slotsize; if (enduseful < ss.slotoffset + ss.slotsize) enduseful = ss.slotoffset + ss.slotsize; } dp->i_endoff = roundup2(enduseful, DIRBLKSIZ); /* * We return with the directory locked, so that * the parameters we set up above will still be * valid if we actually decide to do a direnter(). * We return ni_vp == NULL to indicate that the entry * does not currently exist; we leave a pointer to * the (locked) directory inode in ndp->ni_dvp. * * NB - if the directory is unlocked, then this * information cannot be used. */ return (EJUSTRETURN); } /* * Insert name into cache (as non-existent) if appropriate. */ if ((cnp->cn_flags & MAKEENTRY) != 0) cache_enter(vdp, NULL, cnp); return (ENOENT); found: if (dd_ino != NULL) *dd_ino = ino; if (numdirpasses == 2) nchstats.ncs_pass2++; /* * Check that directory length properly reflects presence * of this entry. */ if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->e2d_namlen) > dp->i_size) { ext2_dirbad(dp, i_offset, "i_size too small"); brelse(bp); return (EIO); } brelse(bp); /* * Found component in pathname. * If the final component of path name, save information * in the cache as to where the entry was found. */ if ((flags & ISLASTCN) && nameiop == LOOKUP) dp->i_diroff = rounddown2(i_offset, DIRBLKSIZ); /* * If deleting, and at end of pathname, return * parameters which can be used to remove file. */ if (nameiop == DELETE && (flags & ISLASTCN)) { if (flags & LOCKPARENT) ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); /* * Write access to directory required to delete files. */ if ((error = VOP_ACCESS(vdp, VWRITE, cred, curthread)) != 0) return (error); /* * Return pointer to current entry in dp->i_offset, * and distance past previous entry (if there * is a previous entry in this block) in dp->i_count. * Save directory inode pointer in ndp->ni_dvp for dirremove(). * * Technically we shouldn't be setting these in the * WANTPARENT case (first lookup in rename()), but any * lookups that will result in directory changes will * overwrite these. */ dp->i_offset = i_offset; if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) dp->i_count = 0; else dp->i_count = dp->i_offset - prevoff; if (dd_ino != NULL) return (0); if (dp->i_number == ino) { - VREF(vdp); + vref(vdp); *vpp = vdp; return (0); } if ((error = VFS_VGET(vdp->v_mount, ino, LK_EXCLUSIVE, &tdp)) != 0) return (error); /* * If directory is "sticky", then user must own * the directory, or the file in it, else she * may not delete it (unless she's root). This * implements append-only directories. */ if ((dp->i_mode & ISVTX) && cred->cr_uid != 0 && cred->cr_uid != dp->i_uid && VTOI(tdp)->i_uid != cred->cr_uid) { vput(tdp); return (EPERM); } *vpp = tdp; return (0); } /* * If rewriting (RENAME), return the inode and the * information required to rewrite the present directory * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ if (nameiop == RENAME && (flags & ISLASTCN)) { if ((error = VOP_ACCESS(vdp, VWRITE, cred, curthread)) != 0) return (error); /* * Careful about locking second inode. * This can only occur if the target is ".". */ dp->i_offset = i_offset; if (dp->i_number == ino) return (EISDIR); if (dd_ino != NULL) return (0); if ((error = VFS_VGET(vdp->v_mount, ino, LK_EXCLUSIVE, &tdp)) != 0) return (error); *vpp = tdp; return (0); } if (dd_ino != NULL) return (0); /* * Step through the translation in the name. We do not `vput' the * directory because we may need it again if a symbolic link * is relative to the current directory. Instead we save it * unlocked as "pdp". We must get the target inode before unlocking * the directory to insure that the inode will not be removed * before we get it. We prevent deadlock by always fetching * inodes from the root, moving down the directory tree. Thus * when following backward pointers ".." we must unlock the * parent directory before getting the requested directory. * There is a potential race condition here if both the current * and parent directories are removed before the VFS_VGET for the * inode associated with ".." returns. We hope that this occurs * infrequently since we cannot avoid this race condition without * implementing a sophisticated deadlock detection algorithm. * Note also that this simple deadlock detection scheme will not * work if the file system has any hard links other than ".." * that point backwards in the directory structure. */ pdp = vdp; if (flags & ISDOTDOT) { error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp); if (VN_IS_DOOMED(pdp)) { if (error == 0) vput(tdp); error = ENOENT; } if (error) return (error); /* * Recheck that ".." entry in the vdp directory points * to the inode we looked up before vdp lock was * dropped. */ error = ext2_lookup_ino(pdp, NULL, cnp, &ino1); if (error) { vput(tdp); return (error); } if (ino1 != ino) { vput(tdp); goto restart; } *vpp = tdp; } else if (dp->i_number == ino) { - VREF(vdp); /* we want ourself, ie "." */ + vref(vdp); /* we want ourself, ie "." */ /* * When we lookup "." we still can be asked to lock it * differently. */ ltype = cnp->cn_lkflags & LK_TYPE_MASK; if (ltype != VOP_ISLOCKED(vdp)) { if (ltype == LK_EXCLUSIVE) vn_lock(vdp, LK_UPGRADE | LK_RETRY); else /* if (ltype == LK_SHARED) */ vn_lock(vdp, LK_DOWNGRADE | LK_RETRY); } *vpp = vdp; } else { if ((error = VFS_VGET(vdp->v_mount, ino, cnp->cn_lkflags, &tdp)) != 0) return (error); *vpp = tdp; } /* * Insert name into cache if appropriate. */ if (cnp->cn_flags & MAKEENTRY) cache_enter(vdp, *vpp, cnp); return (0); } int ext2_search_dirblock(struct inode *ip, void *data, int *foundp, const char *name, int namelen, int *entryoffsetinblockp, doff_t *offp, doff_t *prevoffp, doff_t *endusefulp, struct ext2fs_searchslot *ssp) { struct vnode *vdp; struct ext2fs_direct_2 *ep, *top; uint32_t bsize = ip->i_e2fs->e2fs_bsize; int offset = *entryoffsetinblockp; int namlen; vdp = ITOV(ip); ep = (struct ext2fs_direct_2 *)((char *)data + offset); top = (struct ext2fs_direct_2 *)((char *)data + bsize); while (ep < top) { if (ext2_check_direntry(vdp, ep, offset)) { int i; ext2_dirbad(ip, *offp, "mangled entry"); i = bsize - (offset & (bsize - 1)); *offp += i; offset += i; ep = (struct ext2fs_direct_2 *)((char *)data + offset); continue; } /* * If an appropriate sized slot has not yet been found, * check to see if one is available. Also accumulate space * in the current block so that we can determine if * compaction is viable. */ if (ssp->slotstatus != FOUND) { int size = le16toh(ep->e2d_reclen); if (ep->e2d_ino != 0) size -= EXT2_DIR_REC_LEN(ep->e2d_namlen); else if (ext2_is_dirent_tail(ip, ep)) size -= sizeof(struct ext2fs_direct_tail); if (size > 0) { if (size >= ssp->slotneeded) { ssp->slotstatus = FOUND; ssp->slotoffset = *offp; ssp->slotsize = le16toh(ep->e2d_reclen); } else if (ssp->slotstatus == NONE) { ssp->slotfreespace += size; if (ssp->slotoffset == -1) ssp->slotoffset = *offp; if (ssp->slotfreespace >= ssp->slotneeded) { ssp->slotstatus = COMPACT; ssp->slotsize = *offp + le16toh(ep->e2d_reclen) - ssp->slotoffset; } } } } /* * Check for a name match. */ if (ep->e2d_ino != 0) { namlen = ep->e2d_namlen; if (namlen == namelen && !bcmp(name, ep->e2d_name, (unsigned)namlen)) { /* * Save directory entry's inode number and * reclen in ndp->ni_ufs area, and release * directory buffer. */ *foundp = 1; return (0); } } *prevoffp = *offp; *offp += le16toh(ep->e2d_reclen); offset += le16toh(ep->e2d_reclen); *entryoffsetinblockp = offset; if (ep->e2d_ino != 0) *endusefulp = *offp; /* * Get pointer to the next entry. */ ep = (struct ext2fs_direct_2 *)((char *)data + offset); } return (0); } void ext2_dirbad(struct inode *ip, doff_t offset, char *how) { SDT_PROBE4(ext2fs, , trace, ext2_dirbad_error, ITOV(ip)->v_mount->mnt_stat.f_mntonname, ip->i_number, offset, how); } /* * Do consistency checking on a directory entry: * record length must be multiple of 4 * entry must fit in rest of its DIRBLKSIZ block * record must be large enough to contain entry * name is not longer than MAXNAMLEN * name must be as long as advertised, and null terminated * inode number less then inode count * if root inode entry, it have correct name */ static int ext2_check_direntry(struct vnode *dp, struct ext2fs_direct_2 *de, int entryoffsetinblock) { struct m_ext2fs *fs = VTOI(dp)->i_e2fs; char *error_msg = NULL; if (le16toh(de->e2d_reclen) < EXT2_DIR_REC_LEN(1)) error_msg = "rec_len is smaller than minimal"; else if (le16toh(de->e2d_reclen) % 4 != 0) error_msg = "rec_len % 4 != 0"; else if (le16toh(de->e2d_reclen) < EXT2_DIR_REC_LEN(de->e2d_namlen)) error_msg = "reclen is too small for name_len"; else if (entryoffsetinblock + le16toh(de->e2d_reclen)> fs->e2fs_bsize) error_msg = "directory entry across blocks"; else if (le32toh(de->e2d_ino) > fs->e2fs->e2fs_icount) error_msg = "directory entry inode out of bounds"; else if (le32toh(de->e2d_ino) == EXT2_ROOTINO && ((de->e2d_namlen != 1 && de->e2d_namlen != 2) || (de->e2d_name[0] != '.') || (de->e2d_namlen == 2 && de->e2d_name[1] != '.'))) error_msg = "bad root directory entry"; if (error_msg != NULL) { SDT_PROBE5(ext2fs, , trace, ext2_dirbadentry_error, error_msg, entryoffsetinblock, le32toh(de->e2d_ino), le16toh(de->e2d_reclen), de->e2d_namlen); } return (error_msg == NULL ? 0 : EINVAL); } /* * Insert an entry into the fresh directory block. * Initialize entry tail if the metadata_csum feature is turned on. */ static int ext2_add_first_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry, struct componentname *cnp) { struct inode *dp; struct iovec aiov; struct uio auio; char* buf = NULL; int dirblksize, error; dp = VTOI(dvp); dirblksize = dp->i_e2fs->e2fs_bsize; if (dp->i_offset & (dirblksize - 1)) panic("ext2_add_first_entry: bad directory offset"); if (EXT2_HAS_RO_COMPAT_FEATURE(dp->i_e2fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { entry->e2d_reclen = htole16(dirblksize - sizeof(struct ext2fs_direct_tail)); buf = malloc(dirblksize, M_TEMP, M_WAITOK); memcpy(buf, entry, EXT2_DIR_REC_LEN(entry->e2d_namlen)); ext2_init_dirent_tail(EXT2_DIRENT_TAIL(buf, dirblksize)); ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)buf); auio.uio_offset = dp->i_offset; auio.uio_resid = dirblksize; aiov.iov_len = auio.uio_resid; aiov.iov_base = (caddr_t)buf; } else { entry->e2d_reclen = htole16(dirblksize); auio.uio_offset = dp->i_offset; auio.uio_resid = EXT2_DIR_REC_LEN(entry->e2d_namlen); aiov.iov_len = auio.uio_resid; aiov.iov_base = (caddr_t)entry; } auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_WRITE; auio.uio_segflg = UIO_SYSSPACE; auio.uio_td = (struct thread *)0; error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); if (error) goto out; dp->i_size = roundup2(dp->i_size, dirblksize); dp->i_flag |= IN_CHANGE; out: free(buf, M_TEMP); return (error); } /* * Write a directory entry after a call to namei, using the parameters * that it left in nameidata. The argument ip is the inode which the new * directory entry will refer to. Dvp is a pointer to the directory to * be written, which was left locked by namei. Remaining parameters * (dp->i_offset, dp->i_count) indicate how the space for the new * entry is to be obtained. */ int ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp) { struct inode *dp; struct ext2fs_direct_2 newdir; int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize; int error; dp = VTOI(dvp); newdir.e2d_ino = htole32(ip->i_number); if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs, EXT2F_INCOMPAT_FTYPE)) { newdir.e2d_namlen = cnp->cn_namelen; newdir.e2d_type = DTTOFT(IFTODT(ip->i_mode)); } else newdir.e2d_namlen = htole16(cnp->cn_namelen); bcopy(cnp->cn_nameptr, newdir.e2d_name, (unsigned)cnp->cn_namelen + 1); if (ext2_htree_has_idx(dp)) { error = ext2_htree_add_entry(dvp, &newdir, cnp); if (error) { dp->i_flag &= ~IN_E3INDEX; dp->i_flag |= IN_CHANGE | IN_UPDATE; } return (error); } if (EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_DIRHASHINDEX) && !ext2_htree_has_idx(dp)) { if ((dp->i_size / DIRBLKSIZ) == 1 && dp->i_offset == DIRBLKSIZ) { /* * Making indexed directory when one block is not * enough to save all entries. */ return ext2_htree_create_index(dvp, cnp, &newdir); } } /* * If dp->i_count is 0, then namei could find no * space in the directory. Here, dp->i_offset will * be on a directory block boundary and we will write the * new entry into a fresh block. */ if (dp->i_count == 0) return ext2_add_first_entry(dvp, &newdir, cnp); error = ext2_add_entry(dvp, &newdir); if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC, cnp->cn_cred, curthread); return (error); } /* * Insert an entry into the directory block. * Compact the contents. */ int ext2_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry) { struct ext2fs_direct_2 *ep, *nep; struct inode *dp; struct buf *bp; u_int dsize; int error, loc, newentrysize, spacefree; char *dirbuf; dp = VTOI(dvp); /* * If dp->i_count is non-zero, then namei found space * for the new entry in the range dp->i_offset to * dp->i_offset + dp->i_count in the directory. * To use this space, we may have to compact the entries located * there, by copying them together towards the beginning of the * block, leaving the free space in one usable chunk at the end. */ /* * Increase size of directory if entry eats into new space. * This should never push the size past a new multiple of * DIRBLKSIZE. * * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. */ if (dp->i_offset + dp->i_count > dp->i_size) dp->i_size = dp->i_offset + dp->i_count; /* * Get the block containing the space for the new directory entry. */ if ((error = ext2_blkatoff(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0) return (error); /* * Find space for the new entry. In the simple case, the entry at * offset base will have the space. If it does not, then namei * arranged that compacting the region dp->i_offset to * dp->i_offset + dp->i_count would yield the * space. */ newentrysize = EXT2_DIR_REC_LEN(entry->e2d_namlen); ep = (struct ext2fs_direct_2 *)dirbuf; dsize = EXT2_DIR_REC_LEN(ep->e2d_namlen); spacefree = le16toh(ep->e2d_reclen) - dsize; for (loc = le16toh(ep->e2d_reclen); loc < dp->i_count; ) { nep = (struct ext2fs_direct_2 *)(dirbuf + loc); if (le32toh(ep->e2d_ino)) { /* trim the existing slot */ ep->e2d_reclen = htole16(dsize); ep = (struct ext2fs_direct_2 *)((char *)ep + dsize); } else { /* overwrite; nothing there; header is ours */ spacefree += dsize; } dsize = EXT2_DIR_REC_LEN(nep->e2d_namlen); spacefree += le16toh(nep->e2d_reclen) - dsize; loc += le16toh(nep->e2d_reclen); bcopy((caddr_t)nep, (caddr_t)ep, dsize); } /* * Update the pointer fields in the previous entry (if any), * copy in the new entry, and write out the block. */ if (ep->e2d_ino == 0) { if (spacefree + dsize < newentrysize) panic("ext2_direnter: compact1"); entry->e2d_reclen = htole16(spacefree + dsize); } else { if (spacefree < newentrysize) panic("ext2_direnter: compact2"); entry->e2d_reclen = htole16(spacefree); ep->e2d_reclen = htole16(dsize); ep = (struct ext2fs_direct_2 *)((char *)ep + dsize); } bcopy((caddr_t)entry, (caddr_t)ep, (u_int)newentrysize); ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)bp->b_data); if (DOINGASYNC(dvp)) { bdwrite(bp); error = 0; } else { error = bwrite(bp); } dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error); } /* * Remove a directory entry after a call to namei, using * the parameters which it left in nameidata. The entry * dp->i_offset contains the offset into the directory of the * entry to be eliminated. The dp->i_count field contains the * size of the previous record in the directory. If this * is 0, the first entry is being deleted, so we need only * zero the inode number to mark the entry as free. If the * entry is not the first in the directory, we must reclaim * the space of the now empty record by adding the record size * to the size of the previous entry. */ int ext2_dirremove(struct vnode *dvp, struct componentname *cnp) { struct inode *dp; struct ext2fs_direct_2 *ep, *rep; struct buf *bp; int error; dp = VTOI(dvp); if (dp->i_count == 0) { /* * First entry in block: set d_ino to zero. */ if ((error = ext2_blkatoff(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) return (error); ep->e2d_ino = 0; ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)bp->b_data); error = bwrite(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error); } /* * Collapse new free space into previous entry. */ if ((error = ext2_blkatoff(dvp, (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0) return (error); /* Set 'rep' to the entry being removed. */ if (dp->i_count == 0) rep = ep; else rep = (struct ext2fs_direct_2 *)((char *)ep + le16toh(ep->e2d_reclen)); ep->e2d_reclen += rep->e2d_reclen; ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)bp->b_data); if (DOINGASYNC(dvp) && dp->i_count != 0) bdwrite(bp); else error = bwrite(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error); } /* * Rewrite an existing directory entry to point at the inode * supplied. The parameters describing the directory entry are * set up by a call to namei. */ int ext2_dirrewrite(struct inode *dp, struct inode *ip, struct componentname *cnp) { struct buf *bp; struct ext2fs_direct_2 *ep; struct vnode *vdp = ITOV(dp); int error; if ((error = ext2_blkatoff(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) return (error); ep->e2d_ino = htole32(ip->i_number); if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs, EXT2F_INCOMPAT_FTYPE)) ep->e2d_type = DTTOFT(IFTODT(ip->i_mode)); else ep->e2d_type = EXT2_FT_UNKNOWN; ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)bp->b_data); error = bwrite(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error); } /* * Check if a directory is empty or not. * Inode supplied must be locked. * * Using a struct dirtemplate here is not precisely * what we want, but better than using a struct direct. * * NB: does not handle corrupted directories. */ int ext2_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred) { off_t off; struct dirtemplate dbuf; struct ext2fs_direct_2 *dp = (struct ext2fs_direct_2 *)&dbuf; int error, namlen; ssize_t count; #define MINDIRSIZ (sizeof(struct dirtemplate) / 2) for (off = 0; off < ip->i_size; off += le16toh(dp->e2d_reclen)) { error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, &count, (struct thread *)0); /* * Since we read MINDIRSIZ, residual must * be 0 unless we're at end of file. */ if (error || count != 0) return (0); /* avoid infinite loops */ if (dp->e2d_reclen == 0) return (0); /* skip empty entries */ if (dp->e2d_ino == 0) continue; /* accept only "." and ".." */ namlen = dp->e2d_namlen; if (namlen > 2) return (0); if (dp->e2d_name[0] != '.') return (0); /* * At this point namlen must be 1 or 2. * 1 implies ".", 2 implies ".." if second * char is also "." */ if (namlen == 1) continue; if (dp->e2d_name[1] == '.' && le32toh(dp->e2d_ino) == parentino) continue; return (0); } return (1); } /* * Check if source directory is in the path of the target directory. * Target is supplied locked, source is unlocked. * The target is always vput before returning. */ int ext2_checkpath(struct inode *source, struct inode *target, struct ucred *cred) { struct vnode *vp; int error, namlen; struct dirtemplate dirbuf; vp = ITOV(target); if (target->i_number == source->i_number) { error = EEXIST; goto out; } if (target->i_number == EXT2_ROOTINO) { error = 0; goto out; } for (;;) { if (vp->v_type != VDIR) { error = ENOTDIR; break; } error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, sizeof(struct dirtemplate), (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL); if (error != 0) break; namlen = dirbuf.dotdot_type; /* like ufs little-endian */ if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || dirbuf.dotdot_name[1] != '.') { error = ENOTDIR; break; } if (le32toh(dirbuf.dotdot_ino) == source->i_number) { error = EINVAL; break; } if (le32toh(dirbuf.dotdot_ino) == EXT2_ROOTINO) break; vput(vp); if ((error = VFS_VGET(vp->v_mount, le32toh(dirbuf.dotdot_ino), LK_EXCLUSIVE, &vp)) != 0) { vp = NULL; break; } } out: if (error == ENOTDIR) SDT_PROBE2(ext2fs, , lookup, trace, 1, "checkpath: .. not a directory"); if (vp != NULL) vput(vp); return (error); } diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c index 00389c927087..35e7ca77c732 100644 --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/sys/fs/ext2fs/ext2_vnops.c @@ -1,2341 +1,2341 @@ /*- * modified for EXT2FS support in Lites 1.1 * * Aug 1995, Godmar Back (gback@cs.utah.edu) * University of Utah, Department of Computer Science */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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_suiddir.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "opt_directio.h" #include #include #include #include #include #include #include #include #include #include #include SDT_PROVIDER_DECLARE(ext2fs); /* * ext2fs trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ SDT_PROBE_DEFINE2(ext2fs, , vnops, trace, "int", "char*"); static int ext2_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *); static void ext2_itimes_locked(struct vnode *); static vop_access_t ext2_access; static int ext2_chmod(struct vnode *, int, struct ucred *, struct thread *); static int ext2_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct thread *); static vop_close_t ext2_close; static vop_create_t ext2_create; static vop_fsync_t ext2_fsync; static vop_getattr_t ext2_getattr; static vop_ioctl_t ext2_ioctl; static vop_link_t ext2_link; static vop_mkdir_t ext2_mkdir; static vop_mknod_t ext2_mknod; static vop_open_t ext2_open; static vop_pathconf_t ext2_pathconf; static vop_print_t ext2_print; static vop_read_t ext2_read; static vop_readlink_t ext2_readlink; static vop_remove_t ext2_remove; static vop_rename_t ext2_rename; static vop_rmdir_t ext2_rmdir; static vop_setattr_t ext2_setattr; static vop_strategy_t ext2_strategy; static vop_symlink_t ext2_symlink; static vop_write_t ext2_write; static vop_deleteextattr_t ext2_deleteextattr; static vop_getextattr_t ext2_getextattr; static vop_listextattr_t ext2_listextattr; static vop_setextattr_t ext2_setextattr; static vop_vptofh_t ext2_vptofh; static vop_close_t ext2fifo_close; /* Global vfs data structures for ext2. */ struct vop_vector ext2_vnodeops = { .vop_default = &default_vnodeops, .vop_access = ext2_access, .vop_bmap = ext2_bmap, .vop_cachedlookup = ext2_lookup, .vop_close = ext2_close, .vop_create = ext2_create, .vop_fsync = ext2_fsync, .vop_getpages = vnode_pager_local_getpages, .vop_getpages_async = vnode_pager_local_getpages_async, .vop_getattr = ext2_getattr, .vop_inactive = ext2_inactive, .vop_ioctl = ext2_ioctl, .vop_link = ext2_link, .vop_lookup = vfs_cache_lookup, .vop_mkdir = ext2_mkdir, .vop_mknod = ext2_mknod, .vop_open = ext2_open, .vop_pathconf = ext2_pathconf, .vop_poll = vop_stdpoll, .vop_print = ext2_print, .vop_read = ext2_read, .vop_readdir = ext2_readdir, .vop_readlink = ext2_readlink, .vop_reallocblks = ext2_reallocblks, .vop_reclaim = ext2_reclaim, .vop_remove = ext2_remove, .vop_rename = ext2_rename, .vop_rmdir = ext2_rmdir, .vop_setattr = ext2_setattr, .vop_strategy = ext2_strategy, .vop_symlink = ext2_symlink, .vop_write = ext2_write, .vop_deleteextattr = ext2_deleteextattr, .vop_getextattr = ext2_getextattr, .vop_listextattr = ext2_listextattr, .vop_setextattr = ext2_setextattr, #ifdef UFS_ACL .vop_getacl = ext2_getacl, .vop_setacl = ext2_setacl, .vop_aclcheck = ext2_aclcheck, #endif /* UFS_ACL */ .vop_vptofh = ext2_vptofh, }; VFS_VOP_VECTOR_REGISTER(ext2_vnodeops); struct vop_vector ext2_fifoops = { .vop_default = &fifo_specops, .vop_access = ext2_access, .vop_close = ext2fifo_close, .vop_fsync = ext2_fsync, .vop_getattr = ext2_getattr, .vop_inactive = ext2_inactive, .vop_pathconf = ext2_pathconf, .vop_print = ext2_print, .vop_read = VOP_PANIC, .vop_reclaim = ext2_reclaim, .vop_setattr = ext2_setattr, .vop_write = VOP_PANIC, .vop_vptofh = ext2_vptofh, }; VFS_VOP_VECTOR_REGISTER(ext2_fifoops); /* * A virgin directory (no blushing please). * Note that the type and namlen fields are reversed relative to ext2. * Also, we don't use `struct odirtemplate', since it would just cause * endianness problems. */ static struct dirtemplate mastertemplate = { 0, htole16(12), 1, EXT2_FT_DIR, ".", 0, htole16(DIRBLKSIZ - 12), 2, EXT2_FT_DIR, ".." }; static struct dirtemplate omastertemplate = { 0, htole16(12), 1, EXT2_FT_UNKNOWN, ".", 0, htole16(DIRBLKSIZ - 12), 2, EXT2_FT_UNKNOWN, ".." }; static void ext2_itimes_locked(struct vnode *vp) { struct inode *ip; struct timespec ts; ASSERT_VI_LOCKED(vp, __func__); ip = VTOI(vp); if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) return; if (VN_ISDEV(vp)) ip->i_flag |= IN_LAZYMOD; else ip->i_flag |= IN_MODIFIED; if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { vfs_timestamp(&ts); if (ip->i_flag & IN_ACCESS) { ip->i_atime = ts.tv_sec; ip->i_atimensec = ts.tv_nsec; } if (ip->i_flag & IN_UPDATE) { ip->i_mtime = ts.tv_sec; ip->i_mtimensec = ts.tv_nsec; ip->i_modrev++; } if (ip->i_flag & IN_CHANGE) { ip->i_ctime = ts.tv_sec; ip->i_ctimensec = ts.tv_nsec; } } ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); } void ext2_itimes(struct vnode *vp) { VI_LOCK(vp); ext2_itimes_locked(vp); VI_UNLOCK(vp); } /* * Create a regular file */ static int ext2_create(struct vop_create_args *ap) { int error; error = ext2_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode), ap->a_dvp, ap->a_vpp, ap->a_cnp); if (error != 0) return (error); if ((ap->a_cnp->cn_flags & MAKEENTRY) != 0) cache_enter(ap->a_dvp, *ap->a_vpp, ap->a_cnp); return (0); } static int ext2_open(struct vop_open_args *ap) { if (VN_ISDEV(ap->a_vp)) return (EOPNOTSUPP); /* * Files marked append-only must be opened for appending. */ if ((VTOI(ap->a_vp)->i_flags & APPEND) && (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) return (EPERM); vnode_create_vobject(ap->a_vp, VTOI(ap->a_vp)->i_size, ap->a_td); return (0); } /* * Close called. * * Update the times on the inode. */ static int ext2_close(struct vop_close_args *ap) { struct vnode *vp = ap->a_vp; VI_LOCK(vp); if (vp->v_usecount > 1) ext2_itimes_locked(vp); VI_UNLOCK(vp); return (0); } static int ext2_access(struct vop_access_args *ap) { struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); accmode_t accmode = ap->a_accmode; int error; /* * Disallow write attempts on read-only file systems; * unless the file is a socket, fifo, or a block or * character device resident on the file system. */ if (accmode & VWRITE) { switch (vp->v_type) { case VDIR: case VLNK: case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; default: break; } } /* If immutable bit set, nobody gets to write it. */ if ((accmode & VWRITE) && (ip->i_flags & SF_IMMUTABLE)) return (EPERM); error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, ap->a_accmode, ap->a_cred); return (error); } static int ext2_getattr(struct vop_getattr_args *ap) { struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); struct vattr *vap = ap->a_vap; ext2_itimes(vp); /* * Copy from inode table */ vap->va_fsid = dev2udev(ip->i_devvp->v_rdev); vap->va_fileid = ip->i_number; vap->va_mode = ip->i_mode & ~IFMT; vap->va_nlink = ip->i_nlink; vap->va_uid = ip->i_uid; vap->va_gid = ip->i_gid; 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; vap->va_mtime.tv_sec = ip->i_mtime; vap->va_mtime.tv_nsec = E2DI_HAS_XTIME(ip) ? ip->i_mtimensec : 0; vap->va_ctime.tv_sec = ip->i_ctime; vap->va_ctime.tv_nsec = E2DI_HAS_XTIME(ip) ? ip->i_ctimensec : 0; if (E2DI_HAS_XTIME(ip)) { vap->va_birthtime.tv_sec = ip->i_birthtime; vap->va_birthtime.tv_nsec = ip->i_birthnsec; } vap->va_flags = ip->i_flags; vap->va_gen = ip->i_gen; vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; vap->va_bytes = dbtob((u_quad_t)ip->i_blocks); vap->va_type = IFTOVT(ip->i_mode); vap->va_filerev = ip->i_modrev; return (0); } /* * Set attribute vnode op. called from several syscalls */ static int ext2_setattr(struct vop_setattr_args *ap) { struct vattr *vap = ap->a_vap; struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); struct ucred *cred = ap->a_cred; struct thread *td = curthread; int error; /* * Check for unsettable attributes. */ if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { return (EINVAL); } if (vap->va_flags != VNOVAL) { /* Disallow flags not supported by ext2fs. */ if (vap->va_flags & ~(SF_APPEND | SF_IMMUTABLE | UF_NODUMP)) return (EOPNOTSUPP); if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); /* * Callers may only modify the file flags on objects they * have VADMIN rights for. */ if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) return (error); /* * Unprivileged processes and privileged processes in * jail() are not permitted to unset system flags, or * modify flags if any system flags are set. * Privileged non-jail processes may not modify system flags * if securelevel > 0 and any existing system flags are set. */ if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS)) { if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) { error = securelevel_gt(cred, 0); if (error) return (error); } } else { if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND) || ((vap->va_flags ^ ip->i_flags) & SF_SETTABLE)) return (EPERM); } ip->i_flags = vap->va_flags; ip->i_flag |= IN_CHANGE; if (ip->i_flags & (IMMUTABLE | APPEND)) return (0); } if (ip->i_flags & (IMMUTABLE | APPEND)) return (EPERM); /* * Go through the fields and update iff not VNOVAL. */ if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); if ((error = ext2_chown(vp, vap->va_uid, vap->va_gid, cred, td)) != 0) return (error); } if (vap->va_size != VNOVAL) { /* * Disallow write attempts on read-only file systems; * unless the file is a socket, fifo, or a block or * character device resident on the file system. */ switch (vp->v_type) { case VDIR: return (EISDIR); case VLNK: case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; default: break; } if ((error = ext2_truncate(vp, vap->va_size, 0, cred, td)) != 0) return (error); } if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); /* * From utimes(2): * If times is NULL, ... The caller must be the owner of * the file, have permission to write the file, or be the * super-user. * If times is non-NULL, ... The caller must be the owner of * the file or be the super-user. */ if ((error = VOP_ACCESS(vp, VADMIN, cred, td)) && ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || (error = VOP_ACCESS(vp, VWRITE, cred, td)))) return (error); ip->i_flag |= IN_CHANGE | IN_MODIFIED; if (vap->va_atime.tv_sec != VNOVAL) { ip->i_flag &= ~IN_ACCESS; ip->i_atime = vap->va_atime.tv_sec; ip->i_atimensec = vap->va_atime.tv_nsec; } if (vap->va_mtime.tv_sec != VNOVAL) { ip->i_flag &= ~IN_UPDATE; ip->i_mtime = vap->va_mtime.tv_sec; ip->i_mtimensec = vap->va_mtime.tv_nsec; } if (E2DI_HAS_XTIME(ip) && vap->va_birthtime.tv_sec != VNOVAL) { ip->i_birthtime = vap->va_birthtime.tv_sec; ip->i_birthnsec = vap->va_birthtime.tv_nsec; } error = ext2_update(vp, 0); if (error) return (error); } error = 0; if (vap->va_mode != (mode_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); error = ext2_chmod(vp, (int)vap->va_mode, cred, td); } return (error); } /* * Change the mode on a file. * Inode must be locked before calling. */ static int ext2_chmod(struct vnode *vp, int mode, struct ucred *cred, struct thread *td) { struct inode *ip = VTOI(vp); int error; /* * To modify the permissions on a file, must possess VADMIN * for that file. */ if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) return (error); /* * Privileged processes may set the sticky bit on non-directories, * as well as set the setgid bit on a file with a group that the * process is not a member of. */ if (vp->v_type != VDIR && (mode & S_ISTXT)) { error = priv_check_cred(cred, PRIV_VFS_STICKYFILE); if (error) return (EFTYPE); } if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) { error = priv_check_cred(cred, PRIV_VFS_SETGID); if (error) return (error); } ip->i_mode &= ~ALLPERMS; ip->i_mode |= (mode & ALLPERMS); ip->i_flag |= IN_CHANGE; return (0); } /* * Perform chown operation on inode ip; * inode must be locked prior to call. */ static int ext2_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct thread *td) { struct inode *ip = VTOI(vp); uid_t ouid; gid_t ogid; int error = 0; if (uid == (uid_t)VNOVAL) uid = ip->i_uid; if (gid == (gid_t)VNOVAL) gid = ip->i_gid; /* * To modify the ownership of a file, must possess VADMIN * for that file. */ if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) return (error); /* * To change the owner of a file, or change the group of a file * to a group of which we are not a member, the caller must * have privilege. */ if (uid != ip->i_uid || (gid != ip->i_gid && !groupmember(gid, cred))) { error = priv_check_cred(cred, PRIV_VFS_CHOWN); if (error) return (error); } ogid = ip->i_gid; ouid = ip->i_uid; ip->i_gid = gid; ip->i_uid = uid; ip->i_flag |= IN_CHANGE; if ((ip->i_mode & (ISUID | ISGID)) && (ouid != uid || ogid != gid)) { if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID) != 0) ip->i_mode &= ~(ISUID | ISGID); } return (0); } /* * Synch an open file. */ /* ARGSUSED */ static int ext2_fsync(struct vop_fsync_args *ap) { /* * Flush all dirty buffers associated with a vnode. */ vop_stdfsync(ap); return (ext2_update(ap->a_vp, ap->a_waitfor == MNT_WAIT)); } static int ext2_check_mknod_limits(dev_t dev) { unsigned maj = major(dev); unsigned min = minor(dev); if (maj > EXT2_MAJOR_MAX || min > EXT2_MINOR_MAX) return (EINVAL); return (0); } /* * Mknod vnode call */ /* ARGSUSED */ static int ext2_mknod(struct vop_mknod_args *ap) { struct vattr *vap = ap->a_vap; struct vnode **vpp = ap->a_vpp; struct inode *ip; ino_t ino; int error; if (vap->va_rdev != VNOVAL) { error = ext2_check_mknod_limits(vap->va_rdev); if (error) return (error); } error = ext2_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), ap->a_dvp, vpp, ap->a_cnp); if (error) return (error); ip = VTOI(*vpp); ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; if (vap->va_rdev != VNOVAL) ip->i_rdev = vap->va_rdev; /* * Remove inode, then reload it through VFS_VGET so it is * checked to see if it is an alias of an existing entry in * the inode cache. XXX I don't believe this is necessary now. */ (*vpp)->v_type = VNON; ino = ip->i_number; /* Save this before vgone() invalidates ip. */ vgone(*vpp); vput(*vpp); error = VFS_VGET(ap->a_dvp->v_mount, ino, LK_EXCLUSIVE, vpp); if (error) { *vpp = NULL; return (error); } return (0); } static int ext2_remove(struct vop_remove_args *ap) { struct inode *ip; struct vnode *vp = ap->a_vp; struct vnode *dvp = ap->a_dvp; int error; ip = VTOI(vp); if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || (VTOI(dvp)->i_flags & APPEND)) { error = EPERM; goto out; } error = ext2_dirremove(dvp, ap->a_cnp); if (error == 0) { ip->i_nlink--; ip->i_flag |= IN_CHANGE; } out: return (error); } /* * link vnode call */ static int ext2_link(struct vop_link_args *ap) { struct vnode *vp = ap->a_vp; struct vnode *tdvp = ap->a_tdvp; struct componentname *cnp = ap->a_cnp; struct inode *ip; int error; ip = VTOI(vp); if ((nlink_t)ip->i_nlink >= EXT4_LINK_MAX) { error = EMLINK; goto out; } if (ip->i_flags & (IMMUTABLE | APPEND)) { error = EPERM; goto out; } ip->i_nlink++; ip->i_flag |= IN_CHANGE; error = ext2_update(vp, !DOINGASYNC(vp)); if (!error) error = ext2_direnter(ip, tdvp, cnp); if (error) { ip->i_nlink--; ip->i_flag |= IN_CHANGE; } out: return (error); } static int ext2_inc_nlink(struct inode *ip) { ip->i_nlink++; if (S_ISDIR(ip->i_mode) && EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_DIR_NLINK) && ip->i_nlink > 1) { if (ip->i_nlink >= EXT4_LINK_MAX || ip->i_nlink == 2) ip->i_nlink = 1; } else if (ip->i_nlink > EXT4_LINK_MAX) { ip->i_nlink--; return (EMLINK); } return (0); } static void ext2_dec_nlink(struct inode *ip) { if (!S_ISDIR(ip->i_mode) || ip->i_nlink > 2) ip->i_nlink--; } /* * Rename system call. * rename("foo", "bar"); * is essentially * unlink("bar"); * link("foo", "bar"); * unlink("foo"); * but ``atomically''. Can't do full commit without saving state in the * inode on disk which isn't feasible at this time. Best we can do is * always guarantee the target exists. * * Basic algorithm is: * * 1) Bump link count on source while we're linking it to the * target. This also ensure the inode won't be deleted out * from underneath us while we work (it may be truncated by * a concurrent `trunc' or `open' for creation). * 2) Link source to destination. If destination already exists, * delete it first. * 3) Unlink source reference to inode if still around. If a * directory was moved and the parent of the destination * is different from the source, patch the ".." entry in the * directory. */ static int ext2_rename(struct vop_rename_args *ap) { struct vnode *tvp = ap->a_tvp; struct vnode *tdvp = ap->a_tdvp; struct vnode *fvp = ap->a_fvp; struct vnode *fdvp = ap->a_fdvp; struct componentname *tcnp = ap->a_tcnp; struct componentname *fcnp = ap->a_fcnp; struct inode *ip, *xp, *dp; struct dirtemplate *dirbuf; int doingdirectory = 0, oldparent = 0, newparent = 0; int error = 0; u_char namlen; /* * Check for cross-device rename. */ if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { error = EXDEV; abortit: if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp) vput(tvp); vrele(fdvp); vrele(fvp); return (error); } if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || (VTOI(tdvp)->i_flags & APPEND))) { error = EPERM; goto abortit; } /* * Renaming a file to itself has no effect. The upper layers should * not call us in that case. Temporarily just warn if they do. */ if (fvp == tvp) { SDT_PROBE2(ext2fs, , vnops, trace, 1, "rename: fvp == tvp (can't happen)"); error = 0; goto abortit; } if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) goto abortit; dp = VTOI(fdvp); ip = VTOI(fvp); if (ip->i_nlink >= EXT4_LINK_MAX && !EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_DIR_NLINK)) { VOP_UNLOCK(fvp); error = EMLINK; goto abortit; } if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || (dp->i_flags & APPEND)) { VOP_UNLOCK(fvp); error = EPERM; goto abortit; } if ((ip->i_mode & IFMT) == IFDIR) { /* * Avoid ".", "..", and aliases of "." for obvious reasons. */ if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT || (ip->i_flag & IN_RENAME)) { VOP_UNLOCK(fvp); error = EINVAL; goto abortit; } ip->i_flag |= IN_RENAME; oldparent = dp->i_number; doingdirectory++; } vrele(fdvp); /* * When the target exists, both the directory * and target vnodes are returned locked. */ dp = VTOI(tdvp); xp = NULL; if (tvp) xp = VTOI(tvp); /* * 1) Bump link count while we're moving stuff * around. If we crash somewhere before * completing our work, the link count * may be wrong, but correctable. */ ext2_inc_nlink(ip); ip->i_flag |= IN_CHANGE; if ((error = ext2_update(fvp, !DOINGASYNC(fvp))) != 0) { VOP_UNLOCK(fvp); goto bad; } /* * If ".." must be changed (ie the directory gets a new * parent) then the source directory must not be in the * directory hierarchy above the target, as this would * orphan everything below the source directory. Also * the user must have write permission in the source so * as to be able to change "..". We must repeat the call * to namei, as the parent directory is unlocked by the * call to checkpath(). */ error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, curthread); VOP_UNLOCK(fvp); if (oldparent != dp->i_number) newparent = dp->i_number; if (doingdirectory && newparent) { if (error) /* write access check above */ goto bad; if (xp != NULL) vput(tvp); error = ext2_checkpath(ip, dp, tcnp->cn_cred); if (error) goto out; - VREF(tdvp); + vref(tdvp); error = vfs_relookup(tdvp, &tvp, tcnp, true); if (error) goto out; vrele(tdvp); dp = VTOI(tdvp); xp = NULL; if (tvp) xp = VTOI(tvp); } /* * 2) If target doesn't exist, link the target * to the source and unlink the source. * Otherwise, rewrite the target directory * entry to reference the source inode and * expunge the original entry's existence. */ if (xp == NULL) { if (dp->i_devvp != ip->i_devvp) panic("ext2_rename: EXDEV"); /* * Account for ".." in new directory. * When source and destination have the same * parent we don't fool with the link count. */ if (doingdirectory && newparent) { error = ext2_inc_nlink(dp); if (error) goto bad; dp->i_flag |= IN_CHANGE; error = ext2_update(tdvp, !DOINGASYNC(tdvp)); if (error) goto bad; } error = ext2_direnter(ip, tdvp, tcnp); if (error) { if (doingdirectory && newparent) { ext2_dec_nlink(dp); dp->i_flag |= IN_CHANGE; (void)ext2_update(tdvp, 1); } goto bad; } vput(tdvp); } else { if (xp->i_devvp != dp->i_devvp || xp->i_devvp != ip->i_devvp) panic("ext2_rename: EXDEV"); /* * Short circuit rename(foo, foo). */ if (xp->i_number == ip->i_number) panic("ext2_rename: same file"); /* * If the parent directory is "sticky", then the user must * own the parent directory, or the destination of the rename, * otherwise the destination may not be changed (except by * root). This implements append-only directories. */ if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 && tcnp->cn_cred->cr_uid != dp->i_uid && xp->i_uid != tcnp->cn_cred->cr_uid) { error = EPERM; goto bad; } /* * Target must be empty if a directory and have no links * to it. Also, ensure source and target are compatible * (both directories, or both not directories). */ if ((xp->i_mode & IFMT) == IFDIR) { if (!ext2_dirempty(xp, dp->i_number, tcnp->cn_cred)) { error = ENOTEMPTY; goto bad; } if (!doingdirectory) { error = ENOTDIR; goto bad; } cache_purge(tdvp); } else if (doingdirectory) { error = EISDIR; goto bad; } error = ext2_dirrewrite(dp, ip, tcnp); if (error) goto bad; /* * If the target directory is in the same * directory as the source directory, * decrement the link count on the parent * of the target directory. */ if (doingdirectory && !newparent) { ext2_dec_nlink(dp); dp->i_flag |= IN_CHANGE; } vput(tdvp); /* * Adjust the link count of the target to * reflect the dirrewrite above. If this is * a directory it is empty and there are * no links to it, so we can squash the inode and * any space associated with it. We disallowed * renaming over top of a directory with links to * it above, as the remaining link would point to * a directory without "." or ".." entries. */ ext2_dec_nlink(xp); if (doingdirectory) { if (xp->i_nlink > 2) panic("ext2_rename: linked directory"); error = ext2_truncate(tvp, (off_t)0, IO_SYNC, tcnp->cn_cred, curthread); xp->i_nlink = 0; } xp->i_flag |= IN_CHANGE; vput(tvp); xp = NULL; } /* * 3) Unlink the source. */ fcnp->cn_flags &= ~MODMASK; fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; - VREF(fdvp); + vref(fdvp); error = vfs_relookup(fdvp, &fvp, fcnp, true); if (error == 0) vrele(fdvp); if (fvp != NULL) { xp = VTOI(fvp); dp = VTOI(fdvp); } else { /* * From name has disappeared. IN_RENAME is not sufficient * to protect against directory races due to timing windows, * so we can't panic here. */ vrele(ap->a_fvp); return (0); } /* * Ensure that the directory entry still exists and has not * changed while the new name has been entered. If the source is * a file then the entry may have been unlinked or renamed. In * either case there is no further work to be done. If the source * is a directory then it cannot have been rmdir'ed; its link * count of three would cause a rmdir to fail with ENOTEMPTY. * The IN_RENAME flag ensures that it cannot be moved by another * rename. */ if (xp != ip) { /* * From name resolves to a different inode. IN_RENAME is * not sufficient protection against timing window races * so we can't panic here. */ } else { /* * If the source is a directory with a * new parent, the link count of the old * parent directory must be decremented * and ".." set to point to the new parent. */ if (doingdirectory && newparent) { ext2_dec_nlink(dp); dp->i_flag |= IN_CHANGE; dirbuf = malloc(dp->i_e2fs->e2fs_bsize, M_TEMP, M_WAITOK | M_ZERO); error = vn_rdwr(UIO_READ, fvp, (caddr_t)dirbuf, ip->i_e2fs->e2fs_bsize, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, tcnp->cn_cred, NOCRED, NULL, NULL); if (error == 0) { /* Like ufs little-endian: */ namlen = dirbuf->dotdot_type; if (namlen != 2 || dirbuf->dotdot_name[0] != '.' || dirbuf->dotdot_name[1] != '.') { /* * The filesystem is in corrupted state, * need to run fsck to fix mangled dir * entry. From other side this error * need to be ignored because it is * too difficult to revert directories * to state before rename from this * point. */ ext2_dirbad(xp, (doff_t)12, "rename: mangled dir"); } else { dirbuf->dotdot_ino = htole32(newparent); /* * dirblock 0 could be htree root, * try both csum update functions. */ ext2_dirent_csum_set(ip, (struct ext2fs_direct_2 *)dirbuf); ext2_dx_csum_set(ip, (struct ext2fs_direct_2 *)dirbuf); (void)vn_rdwr(UIO_WRITE, fvp, (caddr_t)dirbuf, ip->i_e2fs->e2fs_bsize, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_SYNC | IO_NOMACCHECK, tcnp->cn_cred, NOCRED, NULL, NULL); cache_purge(fdvp); } } free(dirbuf, M_TEMP); } error = ext2_dirremove(fdvp, fcnp); if (!error) { ext2_dec_nlink(xp); xp->i_flag |= IN_CHANGE; } xp->i_flag &= ~IN_RENAME; } if (dp) vput(fdvp); if (xp) vput(fvp); vrele(ap->a_fvp); return (error); bad: if (xp) vput(ITOV(xp)); vput(ITOV(dp)); out: if (doingdirectory) ip->i_flag &= ~IN_RENAME; if (vn_lock(fvp, LK_EXCLUSIVE) == 0) { ext2_dec_nlink(ip); ip->i_flag |= IN_CHANGE; ip->i_flag &= ~IN_RENAME; vput(fvp); } else vrele(fvp); return (error); } #ifdef UFS_ACL static int ext2_do_posix1e_acl_inheritance_dir(struct vnode *dvp, struct vnode *tvp, mode_t dmode, struct ucred *cred, struct thread *td) { int error; struct inode *ip = VTOI(tvp); struct acl *dacl, *acl; acl = acl_alloc(M_WAITOK); dacl = acl_alloc(M_WAITOK); /* * Retrieve default ACL from parent, if any. */ error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred, td); switch (error) { case 0: /* * Retrieved a default ACL, so merge mode and ACL if * necessary. If the ACL is empty, fall through to * the "not defined or available" case. */ if (acl->acl_cnt != 0) { dmode = acl_posix1e_newfilemode(dmode, acl); ip->i_mode = dmode; *dacl = *acl; ext2_sync_acl_from_inode(ip, acl); break; } /* FALLTHROUGH */ case EOPNOTSUPP: /* * Just use the mode as-is. */ ip->i_mode = dmode; error = 0; goto out; default: goto out; } error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cred, td); if (error == 0) error = VOP_SETACL(tvp, ACL_TYPE_DEFAULT, dacl, cred, td); switch (error) { case 0: break; case EOPNOTSUPP: /* * XXX: This should not happen, as EOPNOTSUPP above * was supposed to free acl. */ #ifdef DEBUG printf("ext2_mkdir: VOP_GETACL() but no VOP_SETACL()\n"); #endif /* DEBUG */ break; default: goto out; } out: acl_free(acl); acl_free(dacl); return (error); } static int ext2_do_posix1e_acl_inheritance_file(struct vnode *dvp, struct vnode *tvp, mode_t mode, struct ucred *cred, struct thread *td) { int error; struct inode *ip = VTOI(tvp); struct acl *acl; acl = acl_alloc(M_WAITOK); /* * Retrieve default ACL for parent, if any. */ error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred, td); switch (error) { case 0: /* * Retrieved a default ACL, so merge mode and ACL if * necessary. */ if (acl->acl_cnt != 0) { /* * Two possible ways for default ACL to not * be present. First, the EA can be * undefined, or second, the default ACL can * be blank. If it's blank, fall through to * the it's not defined case. */ mode = acl_posix1e_newfilemode(mode, acl); ip->i_mode = mode; ext2_sync_acl_from_inode(ip, acl); break; } /* FALLTHROUGH */ case EOPNOTSUPP: /* * Just use the mode as-is. */ ip->i_mode = mode; error = 0; goto out; default: goto out; } error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cred, td); switch (error) { case 0: break; case EOPNOTSUPP: /* * XXX: This should not happen, as EOPNOTSUPP above was * supposed to free acl. */ printf("ufs_do_posix1e_acl_inheritance_file: VOP_GETACL() " "but no VOP_SETACL()\n"); /* panic("ufs_do_posix1e_acl_inheritance_file: VOP_GETACL() " "but no VOP_SETACL()"); */ break; default: goto out; } out: acl_free(acl); return (error); } #endif /* UFS_ACL */ /* * Mkdir system call */ static int ext2_mkdir(struct vop_mkdir_args *ap) { struct m_ext2fs *fs; struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct componentname *cnp = ap->a_cnp; struct inode *ip, *dp; struct vnode *tvp; struct dirtemplate dirtemplate, *dtp; char *buf = NULL; int error, dmode; dp = VTOI(dvp); if ((nlink_t)dp->i_nlink >= EXT4_LINK_MAX && !EXT2_HAS_RO_COMPAT_FEATURE(dp->i_e2fs, EXT2F_ROCOMPAT_DIR_NLINK)) { error = EMLINK; goto out; } dmode = vap->va_mode & 0777; dmode |= IFDIR; /* * Must simulate part of ext2_makeinode here to acquire the inode, * but not have it entered in the parent directory. The entry is * made later after writing "." and ".." entries. */ error = ext2_valloc(dvp, dmode, cnp->cn_cred, &tvp); if (error) goto out; ip = VTOI(tvp); fs = ip->i_e2fs; ip->i_gid = dp->i_gid; #ifdef SUIDDIR { /* * if we are hacking owners here, (only do this where told to) * and we are not giving it TOO root, (would subvert quotas) * then go ahead and give it to the other user. * The new directory also inherits the SUID bit. * If user's UID and dir UID are the same, * 'give it away' so that the SUID is still forced on. */ if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) && (dp->i_mode & ISUID) && dp->i_uid) { dmode |= ISUID; ip->i_uid = dp->i_uid; } else { ip->i_uid = cnp->cn_cred->cr_uid; } } #else ip->i_uid = cnp->cn_cred->cr_uid; #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = dmode; tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ ip->i_nlink = 2; if (cnp->cn_flags & ISWHITEOUT) ip->i_flags |= UF_OPAQUE; error = ext2_update(tvp, 1); /* * Bump link count in parent directory * to reflect work done below. Should * be done before reference is created * so reparation is possible if we crash. */ ext2_inc_nlink(dp); dp->i_flag |= IN_CHANGE; error = ext2_update(dvp, !DOINGASYNC(dvp)); if (error) goto bad; /* Initialize directory with "." and ".." from static template. */ if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs, EXT2F_INCOMPAT_FTYPE)) dtp = &mastertemplate; else dtp = &omastertemplate; dirtemplate = *dtp; dirtemplate.dot_ino = htole32(ip->i_number); dirtemplate.dotdot_ino = htole32(dp->i_number); /* * note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE so let's * just redefine it - for this function only */ #undef DIRBLKSIZ #define DIRBLKSIZ VTOI(dvp)->i_e2fs->e2fs_bsize dirtemplate.dotdot_reclen = htole16(DIRBLKSIZ - 12); buf = malloc(DIRBLKSIZ, M_TEMP, M_WAITOK | M_ZERO); if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { dirtemplate.dotdot_reclen = htole16(le16toh(dirtemplate.dotdot_reclen) - sizeof(struct ext2fs_direct_tail)); ext2_init_dirent_tail(EXT2_DIRENT_TAIL(buf, DIRBLKSIZ)); } memcpy(buf, &dirtemplate, sizeof(dirtemplate)); ext2_dirent_csum_set(ip, (struct ext2fs_direct_2 *)buf); error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)buf, DIRBLKSIZ, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_SYNC | IO_NOMACCHECK, cnp->cn_cred, NOCRED, NULL, NULL); if (error) { ext2_dec_nlink(dp); dp->i_flag |= IN_CHANGE; goto bad; } if (DIRBLKSIZ > VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) /* XXX should grow with balloc() */ panic("ext2_mkdir: blksize"); else { ip->i_size = DIRBLKSIZ; ip->i_flag |= IN_CHANGE; } #ifdef UFS_ACL if (dvp->v_mount->mnt_flag & MNT_ACLS) { error = ext2_do_posix1e_acl_inheritance_dir(dvp, tvp, dmode, cnp->cn_cred, curthread); if (error) goto bad; } #endif /* UFS_ACL */ /* Directory set up, now install its entry in the parent directory. */ error = ext2_direnter(ip, dvp, cnp); if (error) { ext2_dec_nlink(dp); dp->i_flag |= IN_CHANGE; } bad: /* * No need to do an explicit VOP_TRUNCATE here, vrele will do this * for us because we set the link count to 0. */ if (error) { ip->i_nlink = 0; ip->i_flag |= IN_CHANGE; vput(tvp); } else *ap->a_vpp = tvp; out: free(buf, M_TEMP); return (error); #undef DIRBLKSIZ #define DIRBLKSIZ DEV_BSIZE } /* * Rmdir system call. */ static int ext2_rmdir(struct vop_rmdir_args *ap) { struct vnode *vp = ap->a_vp; struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; struct inode *ip, *dp; int error; ip = VTOI(vp); dp = VTOI(dvp); /* * Verify the directory is empty (and valid). * (Rmdir ".." won't be valid since * ".." will contain a reference to * the current directory and thus be * non-empty.) */ if (!ext2_dirempty(ip, dp->i_number, cnp->cn_cred)) { error = ENOTEMPTY; goto out; } if ((dp->i_flags & APPEND) || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) { error = EPERM; goto out; } /* * Delete reference to directory before purging * inode. If we crash in between, the directory * will be reattached to lost+found, */ error = ext2_dirremove(dvp, cnp); if (error) goto out; ext2_dec_nlink(dp); dp->i_flag |= IN_CHANGE; cache_purge(dvp); VOP_UNLOCK(dvp); /* * Truncate inode. The only stuff left * in the directory is "." and "..". */ ip->i_nlink = 0; error = ext2_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred, curthread); cache_purge(ITOV(ip)); if (vn_lock(dvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) { VOP_UNLOCK(vp); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); } out: return (error); } /* * symlink -- make a symbolic link */ static int ext2_symlink(struct vop_symlink_args *ap) { struct vnode *vp, **vpp = ap->a_vpp; struct inode *ip; int len, error; error = ext2_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, vpp, ap->a_cnp); if (error) return (error); vp = *vpp; len = strlen(ap->a_target); if (len < VFSTOEXT2(vp->v_mount)->um_e2fs->e2fs_maxsymlinklen) { ip = VTOI(vp); bcopy(ap->a_target, (char *)ip->i_shortlink, len); ip->i_size = len; ip->i_flag |= IN_CHANGE | IN_UPDATE; } else error = vn_rdwr(UIO_WRITE, vp, __DECONST(void *, ap->a_target), len, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, ap->a_cnp->cn_cred, NOCRED, NULL, NULL); if (error) vput(vp); return (error); } /* * Return target name of a symbolic link */ static int ext2_readlink(struct vop_readlink_args *ap) { struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); int isize; isize = ip->i_size; if (isize < VFSTOEXT2(vp->v_mount)->um_e2fs->e2fs_maxsymlinklen) { uiomove((char *)ip->i_shortlink, isize, ap->a_uio); return (0); } return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); } /* * Calculate the logical to physical mapping if not done already, * then call the device strategy routine. * * In order to be able to swap to a file, the ext2_bmaparray() operation may not * deadlock on memory. See ext2_bmap() for details. */ static int ext2_strategy(struct vop_strategy_args *ap) { struct buf *bp = ap->a_bp; struct vnode *vp = ap->a_vp; struct bufobj *bo; daddr_t blkno; int error; if (VN_ISDEV(vp)) panic("ext2_strategy: spec"); if (bp->b_blkno == bp->b_lblkno) { if (VTOI(ap->a_vp)->i_flag & IN_E4EXTENTS) error = ext4_bmapext(vp, bp->b_lblkno, &blkno, NULL, NULL); else error = ext2_bmaparray(vp, bp->b_lblkno, &blkno, NULL, NULL); bp->b_blkno = blkno; if (error) { bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); } if ((long)bp->b_blkno == -1) { bufdone(bp); return (0); } bp->b_iooffset = dbtob(bp->b_blkno); bo = VFSTOEXT2(vp->v_mount)->um_bo; BO_STRATEGY(bo, bp); return (0); } /* * Print out the contents of an inode. */ static int ext2_print(struct vop_print_args *ap) { struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); vn_printf(ip->i_devvp, "\tino %ju", (uintmax_t)ip->i_number); if (vp->v_type == VFIFO) fifo_printinfo(vp); printf("\n"); return (0); } /* * Close wrapper for fifos. * * Update the times on the inode then do device close. */ static int ext2fifo_close(struct vop_close_args *ap) { struct vnode *vp = ap->a_vp; VI_LOCK(vp); if (vp->v_usecount > 1) ext2_itimes_locked(vp); VI_UNLOCK(vp); return (fifo_specops.vop_close(ap)); } /* * Return POSIX pathconf information applicable to ext2 filesystems. */ static int ext2_pathconf(struct vop_pathconf_args *ap) { int error = 0; switch (ap->a_name) { case _PC_LINK_MAX: if (EXT2_HAS_RO_COMPAT_FEATURE(VTOI(ap->a_vp)->i_e2fs, EXT2F_ROCOMPAT_DIR_NLINK)) *ap->a_retval = INT_MAX; else *ap->a_retval = EXT4_LINK_MAX; break; case _PC_NAME_MAX: *ap->a_retval = NAME_MAX; break; case _PC_PIPE_BUF: if (ap->a_vp->v_type == VDIR || ap->a_vp->v_type == VFIFO) *ap->a_retval = PIPE_BUF; else error = EINVAL; break; case _PC_CHOWN_RESTRICTED: *ap->a_retval = 1; break; case _PC_NO_TRUNC: *ap->a_retval = 1; break; #ifdef UFS_ACL case _PC_ACL_EXTENDED: if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS) *ap->a_retval = 1; else *ap->a_retval = 0; break; case _PC_ACL_PATH_MAX: if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS) *ap->a_retval = ACL_MAX_ENTRIES; else *ap->a_retval = 3; break; #endif /* UFS_ACL */ case _PC_MIN_HOLE_SIZE: *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; break; case _PC_PRIO_IO: *ap->a_retval = 0; break; case _PC_SYNC_IO: *ap->a_retval = 0; break; case _PC_ALLOC_SIZE_MIN: *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize; break; case _PC_FILESIZEBITS: *ap->a_retval = 64; break; case _PC_REC_INCR_XFER_SIZE: *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; break; case _PC_REC_MAX_XFER_SIZE: *ap->a_retval = -1; /* means ``unlimited'' */ break; case _PC_REC_MIN_XFER_SIZE: *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; break; case _PC_REC_XFER_ALIGN: *ap->a_retval = PAGE_SIZE; break; case _PC_SYMLINK_MAX: *ap->a_retval = MAXPATHLEN; break; default: error = vop_stdpathconf(ap); break; } return (error); } /* * Vnode operation to remove a named attribute. */ static int ext2_deleteextattr(struct vop_deleteextattr_args *ap) { struct inode *ip; struct m_ext2fs *fs; int error; ip = VTOI(ap->a_vp); fs = ip->i_e2fs; if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) return (EOPNOTSUPP); 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); if (error) return (error); error = ENOATTR; if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) { error = ext2_extattr_inode_delete(ip, ap->a_attrnamespace, ap->a_name); if (error != ENOATTR) return (error); } if (ip->i_facl) error = ext2_extattr_block_delete(ip, ap->a_attrnamespace, ap->a_name); return (error); } /* * Vnode operation to retrieve a named extended attribute. */ static int ext2_getextattr(struct vop_getextattr_args *ap) { struct inode *ip; struct m_ext2fs *fs; int error; ip = VTOI(ap->a_vp); fs = ip->i_e2fs; if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) return (EOPNOTSUPP); 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); if (error) return (error); if (ap->a_size != NULL) *ap->a_size = 0; error = ENOATTR; if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) { error = ext2_extattr_inode_get(ip, ap->a_attrnamespace, ap->a_name, ap->a_uio, ap->a_size); if (error != ENOATTR) return (error); } if (ip->i_facl) error = ext2_extattr_block_get(ip, ap->a_attrnamespace, ap->a_name, ap->a_uio, ap->a_size); return (error); } /* * Vnode operation to retrieve extended attributes on a vnode. */ static int ext2_listextattr(struct vop_listextattr_args *ap) { struct inode *ip; struct m_ext2fs *fs; int error; ip = VTOI(ap->a_vp); fs = ip->i_e2fs; if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) return (EOPNOTSUPP); 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); if (error) return (error); if (ap->a_size != NULL) *ap->a_size = 0; if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) { error = ext2_extattr_inode_list(ip, ap->a_attrnamespace, ap->a_uio, ap->a_size); if (error) return (error); } if (ip->i_facl) error = ext2_extattr_block_list(ip, ap->a_attrnamespace, ap->a_uio, ap->a_size); return (error); } /* * Vnode operation to set a named attribute. */ static int ext2_setextattr(struct vop_setextattr_args *ap) { struct inode *ip; struct m_ext2fs *fs; int error; ip = VTOI(ap->a_vp); fs = ip->i_e2fs; if (!EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_EXT_ATTR)) return (EOPNOTSUPP); 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); if (error) return (error); error = ext2_extattr_valid_attrname(ap->a_attrnamespace, ap->a_name); if (error) return (error); if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) { error = ext2_extattr_inode_set(ip, ap->a_attrnamespace, ap->a_name, ap->a_uio); if (error != ENOSPC) return (error); } error = ext2_extattr_block_set(ip, ap->a_attrnamespace, ap->a_name, ap->a_uio); return (error); } /* * Vnode pointer to File handle */ /* ARGSUSED */ static int ext2_vptofh(struct vop_vptofh_args *ap) { struct inode *ip; struct ufid *ufhp; _Static_assert(sizeof(struct ufid) <= sizeof(struct fid), "struct ufid cannot be larger than struct fid"); ip = VTOI(ap->a_vp); ufhp = (struct ufid *)ap->a_fhp; ufhp->ufid_len = sizeof(struct ufid); ufhp->ufid_ino = ip->i_number; ufhp->ufid_gen = ip->i_gen; return (0); } /* * Initialize the vnode associated with a new inode, handle aliased * vnodes. */ int ext2_vinit(struct mount *mntp, struct vop_vector *fifoops, struct vnode **vpp) { struct inode *ip; struct vnode *vp; vp = *vpp; ip = VTOI(vp); vp->v_type = IFTOVT(ip->i_mode); /* * Only unallocated inodes should be of type VNON. */ if (ip->i_mode != 0 && vp->v_type == VNON) return (EINVAL); if (vp->v_type == VFIFO) vp->v_op = fifoops; if (ip->i_number == EXT2_ROOTINO) vp->v_vflag |= VV_ROOT; ip->i_modrev = init_va_filerev(); *vpp = vp; return (0); } /* * Allocate a new inode. */ static int ext2_makeinode(int mode, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) { struct inode *ip, *pdir; struct vnode *tvp; int error; pdir = VTOI(dvp); *vpp = NULL; if ((mode & IFMT) == 0) mode |= IFREG; error = ext2_valloc(dvp, mode, cnp->cn_cred, &tvp); if (error) { return (error); } ip = VTOI(tvp); ip->i_gid = pdir->i_gid; #ifdef SUIDDIR { /* * if we are * not the owner of the directory, * and we are hacking owners here, (only do this where told to) * and we are not giving it TOO root, (would subvert quotas) * then go ahead and give it to the other user. * Note that this drops off the execute bits for security. */ if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) && (pdir->i_mode & ISUID) && (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) { ip->i_uid = pdir->i_uid; mode &= ~07111; } else { ip->i_uid = cnp->cn_cred->cr_uid; } } #else ip->i_uid = cnp->cn_cred->cr_uid; #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = mode; tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ ip->i_nlink = 1; if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred)) { if (priv_check_cred(cnp->cn_cred, PRIV_VFS_RETAINSUGID)) ip->i_mode &= ~ISGID; } if (cnp->cn_flags & ISWHITEOUT) ip->i_flags |= UF_OPAQUE; /* * Make sure inode goes to disk before directory entry. */ error = ext2_update(tvp, !DOINGASYNC(tvp)); if (error) goto bad; #ifdef UFS_ACL if (dvp->v_mount->mnt_flag & MNT_ACLS) { error = ext2_do_posix1e_acl_inheritance_file(dvp, tvp, mode, cnp->cn_cred, curthread); if (error) goto bad; } #endif /* UFS_ACL */ error = ext2_direnter(ip, dvp, cnp); if (error) goto bad; *vpp = tvp; return (0); bad: /* * Write error occurred trying to update the inode * or the directory so must deallocate the inode. */ ip->i_nlink = 0; ip->i_flag |= IN_CHANGE; vput(tvp); return (error); } /* * Vnode op for reading. */ static int ext2_read(struct vop_read_args *ap) { struct vnode *vp; struct inode *ip; struct uio *uio; struct m_ext2fs *fs; struct buf *bp; daddr_t lbn, nextlbn; off_t bytesinfile; long size, xfersize, blkoffset; int error, orig_resid, seqcount; int ioflag; vp = ap->a_vp; uio = ap->a_uio; ioflag = ap->a_ioflag; seqcount = ap->a_ioflag >> IO_SEQSHIFT; ip = VTOI(vp); #ifdef INVARIANTS if (uio->uio_rw != UIO_READ) panic("%s: mode", "ext2_read"); if (vp->v_type == VLNK) { if ((int)ip->i_size < VFSTOEXT2(vp->v_mount)->um_e2fs->e2fs_maxsymlinklen) panic("%s: short symlink", "ext2_read"); } else if (vp->v_type != VREG && vp->v_type != VDIR) panic("%s: type %d", "ext2_read", vp->v_type); #endif orig_resid = uio->uio_resid; KASSERT(orig_resid >= 0, ("ext2_read: uio->uio_resid < 0")); if (orig_resid == 0) return (0); KASSERT(uio->uio_offset >= 0, ("ext2_read: uio->uio_offset < 0")); fs = ip->i_e2fs; if (uio->uio_offset < ip->i_size && uio->uio_offset >= fs->e2fs_maxfilesize) return (EOVERFLOW); for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0) break; lbn = lblkno(fs, uio->uio_offset); nextlbn = lbn + 1; size = blksize(fs, ip, lbn); blkoffset = blkoff(fs, uio->uio_offset); xfersize = fs->e2fs_fsize - blkoffset; if (uio->uio_resid < xfersize) xfersize = uio->uio_resid; if (bytesinfile < xfersize) xfersize = bytesinfile; if (lblktosize(fs, nextlbn) >= ip->i_size) error = bread(vp, lbn, size, NOCRED, &bp); else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { error = cluster_read(vp, ip->i_size, lbn, size, NOCRED, blkoffset + uio->uio_resid, seqcount, 0, &bp); } else if (seqcount > 1) { u_int nextsize = blksize(fs, ip, nextlbn); error = breadn(vp, lbn, size, &nextlbn, &nextsize, 1, NOCRED, &bp); } else error = bread(vp, lbn, size, NOCRED, &bp); if (error) { brelse(bp); bp = NULL; break; } /* * We should only get non-zero b_resid when an I/O error * has occurred, which should cause us to break above. * However, if the short read did not cause an error, * then we want to ensure that we do not uiomove bad * or uninitialized data. */ size -= bp->b_resid; if (size < xfersize) { if (size == 0) break; xfersize = size; } error = uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio); if (error) break; vfs_bio_brelse(bp, ioflag); } /* * This can only happen in the case of an error because the loop * above resets bp to NULL on each iteration and on normal * completion has not set a new value into it. so it must have come * from a 'break' statement */ if (bp != NULL) vfs_bio_brelse(bp, ioflag); if ((error == 0 || uio->uio_resid != orig_resid) && (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0) ip->i_flag |= IN_ACCESS; return (error); } static int ext2_ioctl(struct vop_ioctl_args *ap) { struct vnode *vp; int error; vp = ap->a_vp; switch (ap->a_command) { case FIOSEEKDATA: if (!(VTOI(vp)->i_flag & IN_E4EXTENTS)) { error = vn_lock(vp, LK_SHARED); if (error == 0) { error = ext2_bmap_seekdata(vp, (off_t *)ap->a_data); VOP_UNLOCK(vp); } else error = EBADF; return (error); } case FIOSEEKHOLE: return (vn_bmap_seekhole(vp, ap->a_command, (off_t *)ap->a_data, ap->a_cred)); default: return (ENOTTY); } } /* * Vnode op for writing. */ static int ext2_write(struct vop_write_args *ap) { struct vnode *vp; struct uio *uio; struct inode *ip; struct m_ext2fs *fs; struct buf *bp; daddr_t lbn; off_t osize; int blkoffset, error, flags, ioflag, resid, size, seqcount, xfersize; ioflag = ap->a_ioflag; uio = ap->a_uio; vp = ap->a_vp; seqcount = ioflag >> IO_SEQSHIFT; ip = VTOI(vp); #ifdef INVARIANTS if (uio->uio_rw != UIO_WRITE) panic("%s: mode", "ext2_write"); #endif switch (vp->v_type) { case VREG: if (ioflag & IO_APPEND) uio->uio_offset = ip->i_size; if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size) return (EPERM); /* FALLTHROUGH */ case VLNK: break; case VDIR: /* XXX differs from ffs -- this is called from ext2_mkdir(). */ if ((ioflag & IO_SYNC) == 0) panic("ext2_write: nonsync dir write"); break; default: panic("ext2_write: type %p %d (%jd,%jd)", (void *)vp, vp->v_type, (intmax_t)uio->uio_offset, (intmax_t)uio->uio_resid); } KASSERT(uio->uio_resid >= 0, ("ext2_write: uio->uio_resid < 0")); KASSERT(uio->uio_offset >= 0, ("ext2_write: uio->uio_offset < 0")); fs = ip->i_e2fs; if ((uoff_t)uio->uio_offset + uio->uio_resid > fs->e2fs_maxfilesize) return (EFBIG); /* * Maybe this should be above the vnode op call, but so long as * file servers have no limits, I don't think it matters. */ error = vn_rlimit_fsize(vp, uio, uio->uio_td); if (error != 0) return (error); resid = uio->uio_resid; osize = ip->i_size; if (seqcount > BA_SEQMAX) flags = BA_SEQMAX << BA_SEQSHIFT; else flags = seqcount << BA_SEQSHIFT; if ((ioflag & IO_SYNC) && !DOINGASYNC(vp)) flags |= IO_SYNC; for (error = 0; uio->uio_resid > 0;) { lbn = lblkno(fs, uio->uio_offset); blkoffset = blkoff(fs, uio->uio_offset); xfersize = fs->e2fs_fsize - blkoffset; if (uio->uio_resid < xfersize) xfersize = uio->uio_resid; if (uio->uio_offset + xfersize > ip->i_size) vnode_pager_setsize(vp, uio->uio_offset + xfersize); /* * We must perform a read-before-write if the transfer size * does not cover the entire buffer. */ if (fs->e2fs_bsize > xfersize) flags |= BA_CLRBUF; else flags &= ~BA_CLRBUF; error = ext2_balloc(ip, lbn, blkoffset + xfersize, ap->a_cred, &bp, flags); if (error != 0) break; if ((ioflag & (IO_SYNC | IO_INVAL)) == (IO_SYNC | IO_INVAL)) bp->b_flags |= B_NOCACHE; if (uio->uio_offset + xfersize > ip->i_size) ip->i_size = uio->uio_offset + xfersize; size = blksize(fs, ip, lbn) - bp->b_resid; if (size < xfersize) xfersize = size; error = uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio); /* * If the buffer is not already filled and we encounter an * error while trying to fill it, we have to clear out any * garbage data from the pages instantiated for the buffer. * If we do not, a failed uiomove() during a write can leave * the prior contents of the pages exposed to a userland mmap. * * Note that we need only clear buffers with a transfer size * equal to the block size because buffers with a shorter * transfer size were cleared above by the call to ext2_balloc() * with the BA_CLRBUF flag set. * * If the source region for uiomove identically mmaps the * buffer, uiomove() performed the NOP copy, and the buffer * content remains valid because the page fault handler * validated the pages. */ if (error != 0 && (bp->b_flags & B_CACHE) == 0 && fs->e2fs_bsize == xfersize) vfs_bio_clrbuf(bp); vfs_bio_set_flags(bp, ioflag); /* * If IO_SYNC each buffer is written synchronously. Otherwise * if we have a severe page deficiency write the buffer * asynchronously. Otherwise try to cluster, and if that * doesn't do it then either do an async write (if O_DIRECT), * or a delayed write (if not). */ if (ioflag & IO_SYNC) { (void)bwrite(bp); } else if (vm_page_count_severe() || buf_dirty_count_severe() || (ioflag & IO_ASYNC)) { bp->b_flags |= B_CLUSTEROK; bawrite(bp); } else if (xfersize + blkoffset == fs->e2fs_fsize) { if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) { bp->b_flags |= B_CLUSTEROK; cluster_write(vp, &ip->i_clusterw, bp, ip->i_size, seqcount, 0); } else { bawrite(bp); } } else if (ioflag & IO_DIRECT) { bp->b_flags |= B_CLUSTEROK; bawrite(bp); } else { bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } if (error || xfersize == 0) break; } /* * If we successfully wrote any data, and we are not the superuser * we clear the setuid and setgid bits as a precaution against * tampering. */ if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && ap->a_cred) { if (priv_check_cred(ap->a_cred, PRIV_VFS_RETAINSUGID)) ip->i_mode &= ~(ISUID | ISGID); } if (error) { if (ioflag & IO_UNIT) { (void)ext2_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred, uio->uio_td); uio->uio_offset -= resid - uio->uio_resid; uio->uio_resid = resid; } } if (uio->uio_resid != resid) { ip->i_flag |= IN_CHANGE | IN_UPDATE; if (ioflag & IO_SYNC) error = ext2_update(vp, 1); } return (error); } diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c index 3014136fcbdb..c1188c3819e7 100644 --- a/sys/fs/fdescfs/fdesc_vnops.c +++ b/sys/fs/fdescfs/fdesc_vnops.c @@ -1,674 +1,674 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by * Jan-Simon Pendry. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. */ /* * /dev/fd Filesystem */ #include #include #include #include #include #include #include /* boottime */ #include #include #include #include /* Must come after sys/malloc.h */ #include #include #include #include #include #include #include #include #define NFDCACHE 4 #define FD_NHASH(ix) \ (&fdhashtbl[(ix) & fdhash]) static LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; static u_long fdhash; struct mtx fdesc_hashmtx; static vop_getattr_t fdesc_getattr; static vop_lookup_t fdesc_lookup; static vop_open_t fdesc_open; static vop_pathconf_t fdesc_pathconf; static vop_readdir_t fdesc_readdir; static vop_readlink_t fdesc_readlink; static vop_reclaim_t fdesc_reclaim; static vop_setattr_t fdesc_setattr; static struct vop_vector fdesc_vnodeops = { .vop_default = &default_vnodeops, .vop_access = VOP_NULL, .vop_getattr = fdesc_getattr, .vop_lookup = fdesc_lookup, .vop_open = fdesc_open, .vop_pathconf = fdesc_pathconf, .vop_readdir = fdesc_readdir, .vop_readlink = fdesc_readlink, .vop_reclaim = fdesc_reclaim, .vop_setattr = fdesc_setattr, }; VFS_VOP_VECTOR_REGISTER(fdesc_vnodeops); static void fdesc_remove_entry(struct fdescnode *); /* * Initialise cache headers */ int fdesc_init(struct vfsconf *vfsp) { mtx_init(&fdesc_hashmtx, "fdescfs_hash", NULL, MTX_DEF); fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash); return (0); } /* * Uninit ready for unload. */ int fdesc_uninit(struct vfsconf *vfsp) { hashdestroy(fdhashtbl, M_CACHE, fdhash); mtx_destroy(&fdesc_hashmtx); return (0); } /* * Remove an entry from the hash if it exists. */ static void fdesc_remove_entry(struct fdescnode *fd) { struct fdhashhead *fc; struct fdescnode *fd2; fc = FD_NHASH(fd->fd_ix); mtx_lock(&fdesc_hashmtx); LIST_FOREACH(fd2, fc, fd_hash) { if (fd == fd2) { LIST_REMOVE(fd, fd_hash); break; } } mtx_unlock(&fdesc_hashmtx); } int fdesc_allocvp(fdntype ftype, unsigned fd_fd, int ix, struct mount *mp, struct vnode **vpp) { struct fdescmount *fmp; struct fdhashhead *fc; struct fdescnode *fd, *fd2; struct vnode *vp, *vp2; enum vgetstate vgs; int error; fc = FD_NHASH(ix); loop: mtx_lock(&fdesc_hashmtx); /* * If a forced unmount is progressing, we need to drop it. The flags are * protected by the hashmtx. */ fmp = mp->mnt_data; if (fmp == NULL || fmp->flags & FMNT_UNMOUNTF) { mtx_unlock(&fdesc_hashmtx); return (-1); } LIST_FOREACH(fd, fc, fd_hash) { if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { /* Get reference to vnode in case it's being free'd */ vp = fd->fd_vnode; vgs = vget_prep(vp); mtx_unlock(&fdesc_hashmtx); if (vget_finish(vp, LK_EXCLUSIVE, vgs) != 0) goto loop; *vpp = vp; return (0); } } mtx_unlock(&fdesc_hashmtx); fd = malloc(sizeof(struct fdescnode), M_TEMP, M_WAITOK); error = getnewvnode("fdescfs", mp, &fdesc_vnodeops, &vp); if (error) { free(fd, M_TEMP); return (error); } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vp->v_data = fd; fd->fd_vnode = vp; fd->fd_type = ftype; fd->fd_fd = fd_fd; fd->fd_ix = ix; if (ftype == Fdesc) { if ((fmp->flags & FMNT_RDLNKF) != 0) vp->v_type = VLNK; else if ((fmp->flags & FMNT_LINRDLNKF) != 0) vp->v_vflag |= VV_READLINK; } error = insmntque1(vp, mp); if (error != 0) { vgone(vp); vput(vp); *vpp = NULL; return (error); } /* Make sure that someone didn't beat us when inserting the vnode. */ mtx_lock(&fdesc_hashmtx); /* * If a forced unmount is progressing, we need to drop it. The flags are * protected by the hashmtx. */ fmp = mp->mnt_data; if (fmp == NULL || fmp->flags & FMNT_UNMOUNTF) { mtx_unlock(&fdesc_hashmtx); vgone(vp); vput(vp); *vpp = NULL; return (-1); } LIST_FOREACH(fd2, fc, fd_hash) { if (fd2->fd_ix == ix && fd2->fd_vnode->v_mount == mp) { /* Get reference to vnode in case it's being free'd */ vp2 = fd2->fd_vnode; vgs = vget_prep(vp2); mtx_unlock(&fdesc_hashmtx); error = vget_finish(vp2, LK_EXCLUSIVE, vgs); /* Someone beat us, dec use count and wait for reclaim */ vgone(vp); vput(vp); /* If we didn't get it, return no vnode. */ if (error) vp2 = NULL; *vpp = vp2; return (error); } } /* If we came here, we can insert it safely. */ LIST_INSERT_HEAD(fc, fd, fd_hash); mtx_unlock(&fdesc_hashmtx); vn_set_state(vp, VSTATE_CONSTRUCTED); *vpp = vp; return (0); } struct fdesc_get_ino_args { fdntype ftype; unsigned fd_fd; int ix; struct file *fp; struct thread *td; bool fdropped; }; static int fdesc_get_ino_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **rvp) { struct fdesc_get_ino_args *a; struct fdescmount *fdm; struct vnode *vp; int error; a = arg; fdm = VFSTOFDESC(mp); if ((fdm->flags & FMNT_NODUP) != 0 && a->fp->f_type == DTYPE_VNODE) { vp = a->fp->f_vnode; vget(vp, lkflags | LK_RETRY); *rvp = vp; error = 0; } else { error = fdesc_allocvp(a->ftype, a->fd_fd, a->ix, mp, rvp); } fdrop(a->fp, a->td); a->fdropped = true; return (error); } /* * vp is the current namei directory * ndp is the name to locate in that directory... */ static int fdesc_lookup(struct vop_lookup_args *ap) { struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; char *pname = cnp->cn_nameptr; struct thread *td = curthread; struct file *fp; struct fdesc_get_ino_args arg; int nlen = cnp->cn_namelen; u_int fd, fd1; int error; struct vnode *fvp; if ((cnp->cn_flags & ISLASTCN) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { error = EROFS; goto bad; } if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; - VREF(dvp); + vref(dvp); return (0); } if (VTOFDESC(dvp)->fd_type != Froot) { error = ENOTDIR; goto bad; } fd = 0; /* the only time a leading 0 is acceptable is if it's "0" */ if (*pname == '0' && nlen != 1) { error = ENOENT; goto bad; } while (nlen--) { if (*pname < '0' || *pname > '9') { error = ENOENT; goto bad; } fd1 = 10 * fd + *pname++ - '0'; if (fd1 < fd) { error = ENOENT; goto bad; } fd = fd1; } /* * No rights to check since 'fp' isn't actually used. */ if ((error = fget(td, fd, &cap_no_rights, &fp)) != 0) goto bad; /* * Make sure we do not deadlock looking up the dvp itself. * * Unlock our root node (dvp) when doing this, since we might * deadlock since the vnode might be locked by another thread * and the root vnode lock will be obtained afterwards (in case * we're looking up the fd of the root vnode), which will be the * opposite lock order. */ arg.ftype = Fdesc; arg.fd_fd = fd; arg.ix = FD_DESC + fd; arg.fp = fp; arg.td = td; arg.fdropped = false; error = vn_vget_ino_gen(dvp, fdesc_get_ino_alloc, &arg, LK_EXCLUSIVE, &fvp); if (!arg.fdropped) { /* * In case we're holding the last reference to the file, the dvp * will be re-acquired. */ VOP_UNLOCK(dvp); fdrop(fp, td); vn_lock(dvp, LK_RETRY | LK_EXCLUSIVE); fvp = dvp; if (error == 0 && VN_IS_DOOMED(dvp)) error = ENOENT; } if (error) goto bad; *vpp = fvp; return (0); bad: *vpp = NULL; return (error); } static int fdesc_open(struct vop_open_args *ap) { struct vnode *vp = ap->a_vp; if (VTOFDESC(vp)->fd_type == Froot) return (0); /* * XXX Kludge: set td->td_proc->p_dupfd to contain the value of the file * descriptor being sought for duplication. The error return ensures * that the vnode for this device will be released by vn_open. Open * will detect this special error and take the actions in dupfdopen. * Other callers of vn_open or VOP_OPEN will simply report the * error. */ ap->a_td->td_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ return (ENODEV); } static int fdesc_pathconf(struct vop_pathconf_args *ap) { struct vnode *vp = ap->a_vp; int error; switch (ap->a_name) { case _PC_NAME_MAX: *ap->a_retval = NAME_MAX; return (0); case _PC_LINK_MAX: if (VTOFDESC(vp)->fd_type == Froot) *ap->a_retval = 2; else *ap->a_retval = 1; return (0); default: if (VTOFDESC(vp)->fd_type == Froot) return (vop_stdpathconf(ap)); vref(vp); VOP_UNLOCK(vp); error = kern_fpathconf(curthread, VTOFDESC(vp)->fd_fd, ap->a_name, ap->a_retval); vn_lock(vp, LK_SHARED | LK_RETRY); vunref(vp); return (error); } } static int fdesc_getattr(struct vop_getattr_args *ap) { struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; struct timeval boottime; getboottime(&boottime); vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; vap->va_fileid = VTOFDESC(vp)->fd_ix; vap->va_uid = 0; vap->va_gid = 0; vap->va_blocksize = DEV_BSIZE; vap->va_atime.tv_sec = boottime.tv_sec; vap->va_atime.tv_nsec = 0; vap->va_mtime = vap->va_atime; vap->va_ctime = vap->va_mtime; vap->va_gen = 0; vap->va_flags = 0; vap->va_bytes = 0; vap->va_filerev = 0; switch (VTOFDESC(vp)->fd_type) { case Froot: vap->va_type = VDIR; vap->va_nlink = 2; vap->va_size = DEV_BSIZE; vap->va_rdev = NODEV; break; case Fdesc: vap->va_type = (VFSTOFDESC(vp->v_mount)->flags & (FMNT_RDLNKF | FMNT_LINRDLNKF)) == 0 ? VCHR : VLNK; vap->va_nlink = 1; vap->va_size = 0; vap->va_rdev = makedev(0, vap->va_fileid); break; default: panic("fdesc_getattr"); break; } vp->v_type = vap->va_type; return (0); } static int fdesc_setattr(struct vop_setattr_args *ap) { struct vattr *vap = ap->a_vap; struct vnode *vp; struct mount *mp; struct file *fp; struct thread *td = curthread; cap_rights_t rights; unsigned fd; int error; /* * Can't mess with the root vnode */ if (VTOFDESC(ap->a_vp)->fd_type == Froot) return (EACCES); fd = VTOFDESC(ap->a_vp)->fd_fd; /* * Allow setattr where there is an underlying vnode. * For O_PATH descriptors, disallow truncate. */ if (vap->va_size != VNOVAL) { error = getvnode(td, fd, cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp); } else { error = getvnode_path(td, fd, cap_rights_init_one(&rights, CAP_EXTATTR_SET), NULL, &fp); } if (error) { /* * getvnode() returns EINVAL if the file descriptor is not * backed by a vnode. Silently drop all changes except * chflags(2) in this case. */ if (error == EINVAL) { if (vap->va_flags != VNOVAL) error = EOPNOTSUPP; else error = 0; } return (error); } vp = fp->f_vnode; if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) == 0) { vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_SETATTR(vp, ap->a_vap, ap->a_cred); VOP_UNLOCK(vp); vn_finished_write(mp); } fdrop(fp, td); return (error); } #define UIO_MX _GENERIC_DIRLEN(10) /* number of symbols in INT_MAX printout */ static int fdesc_readdir(struct vop_readdir_args *ap) { struct fdescmount *fmp; struct uio *uio = ap->a_uio; struct filedesc *fdp; struct dirent d; struct dirent *dp = &d; int error, i, off, fcnt; if (VTOFDESC(ap->a_vp)->fd_type != Froot) panic("fdesc_readdir: not dir"); fmp = VFSTOFDESC(ap->a_vp->v_mount); if (ap->a_ncookies != NULL) *ap->a_ncookies = 0; if (ap->a_eofflag != NULL) *ap->a_eofflag = 0; off = (int)uio->uio_offset; if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 || uio->uio_resid < UIO_MX) return (EINVAL); i = (u_int)off / UIO_MX; fdp = uio->uio_td->td_proc->p_fd; error = 0; fcnt = i - 2; /* The first two nodes are `.' and `..' */ FILEDESC_SLOCK(fdp); while (uio->uio_resid >= UIO_MX) { if (i >= fdp->fd_nfiles + 2) { if (ap->a_eofflag != NULL) *ap->a_eofflag = 1; break; } bzero((caddr_t)dp, UIO_MX); switch (i) { case 0: /* `.' */ case 1: /* `..' */ dp->d_fileno = i + FD_ROOT; dp->d_namlen = i + 1; dp->d_reclen = UIO_MX; bcopy("..", dp->d_name, dp->d_namlen); dp->d_type = DT_DIR; dirent_terminate(dp); break; default: if (fdp->fd_ofiles[fcnt].fde_file == NULL) break; dp->d_namlen = sprintf(dp->d_name, "%d", fcnt); dp->d_reclen = UIO_MX; dp->d_type = (fmp->flags & (FMNT_RDLNKF | FMNT_LINRDLNKF)) == 0 ? DT_CHR : DT_LNK; dp->d_fileno = i + FD_DESC; dirent_terminate(dp); break; } /* NOTE: d_off is the offset of the *next* entry. */ dp->d_off = UIO_MX * (i + 1); if (dp->d_namlen != 0) { /* * And ship to userland */ FILEDESC_SUNLOCK(fdp); error = uiomove(dp, UIO_MX, uio); if (error) goto done; FILEDESC_SLOCK(fdp); } i++; fcnt++; } FILEDESC_SUNLOCK(fdp); done: uio->uio_offset = i * UIO_MX; return (error); } static int fdesc_reclaim(struct vop_reclaim_args *ap) { struct vnode *vp; struct fdescnode *fd; vp = ap->a_vp; fd = VTOFDESC(vp); fdesc_remove_entry(fd); free(vp->v_data, M_TEMP); vp->v_data = NULL; return (0); } static int fdesc_readlink(struct vop_readlink_args *va) { struct vnode *vp, *vn; struct thread *td; struct uio *uio; struct file *fp; char *freepath, *fullpath; size_t pathlen; int lockflags, fd_fd; int error; freepath = NULL; vn = va->a_vp; if (VTOFDESC(vn)->fd_type != Fdesc) panic("fdesc_readlink: not fdescfs link"); fd_fd = ((struct fdescnode *)vn->v_data)->fd_fd; lockflags = VOP_ISLOCKED(vn); VOP_UNLOCK(vn); td = curthread; error = fget_cap(td, fd_fd, &cap_no_rights, NULL, &fp, NULL); if (error != 0) goto out; switch (fp->f_type) { case DTYPE_VNODE: vp = fp->f_vnode; error = vn_fullpath(vp, &fullpath, &freepath); break; default: fullpath = "anon_inode:[unknown]"; break; } if (error == 0) { uio = va->a_uio; pathlen = strlen(fullpath); error = uiomove(fullpath, pathlen, uio); } if (freepath != NULL) free(freepath, M_TEMP); fdrop(fp, td); out: vn_lock(vn, lockflags | LK_RETRY); return (error); } diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c index 8ab6d35a2685..58ce8eff9dbd 100644 --- a/sys/fs/msdosfs/msdosfs_lookup.c +++ b/sys/fs/msdosfs/msdosfs_lookup.c @@ -1,1099 +1,1099 @@ /* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $ */ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. * Copyright (C) 1994, 1995, 1997 TooLs GmbH. * All rights reserved. * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. */ /*- * Written by Paul Popelka (paulp@uts.amdahl.com) * * You can do anything you want with this software, just don't say you wrote * it, and don't remove this notice. * * This software is provided "as is". * * The author supplies this software to be publicly redistributed on the * understanding that the author is not responsible for the correct * functioning of this software in any circumstances and is not liable for * any damages caused by this software. * * October 1992 */ #include #include #include #include #include #include #include #include #include #include #include static int msdosfs_lookup_checker(struct msdosfsmount *pmp, struct vnode *dvp, struct denode *tdp, struct vnode **vpp) { struct vnode *vp; vp = DETOV(tdp); /* * Lookup assumes that directory cannot be hardlinked. * Corrupted msdosfs filesystem could break this assumption. */ if (vp == dvp) { vput(vp); msdosfs_integrity_error(pmp); *vpp = NULL; return (EBADF); } *vpp = vp; return (0); } int msdosfs_lookup(struct vop_cachedlookup_args *ap) { return (msdosfs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL, NULL)); } struct deget_dotdot { u_long cluster; int blkoff; }; static int msdosfs_deget_dotdot(struct mount *mp, void *arg, int lkflags, struct vnode **rvp) { struct deget_dotdot *dd_arg; struct denode *rdp; struct msdosfsmount *pmp; int error; pmp = VFSTOMSDOSFS(mp); dd_arg = arg; error = deget(pmp, dd_arg->cluster, dd_arg->blkoff, LK_EXCLUSIVE, &rdp); if (error == 0) *rvp = DETOV(rdp); return (error); } /* * When we search a directory the blocks containing directory entries are * read and examined. The directory entries contain information that would * normally be in the inode of a unix filesystem. This means that some of * a directory's contents may also be in memory resident denodes (sort of * an inode). This can cause problems if we are searching while some other * process is modifying a directory. To prevent one process from accessing * incompletely modified directory information we depend upon being the * sole owner of a directory block. bread/brelse provide this service. * This being the case, when a process modifies a directory it must first * acquire the disk block that contains the directory entry to be modified. * Then update the disk block and the denode, and then write the disk block * out to disk. This way disk blocks containing directory entries and in * memory denode's will be in synch. */ int msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp, daddr_t *scnp, u_long *blkoffp) { struct mbnambuf nb; daddr_t bn; int error; int slotcount; int slotoffset = 0; int frcn; u_long cluster; u_long blkoff; int diroff; int blsize; int isadir; /* ~0 if found direntry is a directory */ daddr_t scn; /* starting cluster number */ struct vnode *pdp; struct denode *dp; struct denode *tdp; struct msdosfsmount *pmp; struct buf *bp = NULL; struct direntry *dep = NULL; struct deget_dotdot dd_arg; u_char dosfilename[12]; int flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; int unlen; uint64_t inode1; int wincnt = 1; int chksum = -1, chksum_ok; int olddos = 1; #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr); #endif dp = VTODE(vdp); pmp = dp->de_pmp; #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n", vdp, dp, dp->de_Attributes); #endif restart: if (vpp != NULL) *vpp = NULL; /* * If they are going after the . or .. entry in the root directory, * they won't find it. DOS filesystems don't have them in the root * directory. So, we fake it. deget() is in on this scam too. */ if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' && (cnp->cn_namelen == 1 || (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) { isadir = ATTR_DIRECTORY; scn = MSDOSFSROOT; #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): looking for . or .. in root directory\n"); #endif cluster = MSDOSFSROOT; blkoff = MSDOSFSROOT_OFS; goto foundroot; } switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, cnp->cn_namelen, 0, pmp)) { case 0: if (nameiop == CREATE || nameiop == RENAME) return (EINVAL); return (ENOENT); case 1: break; case 2: wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, cnp->cn_namelen, pmp) + 1; break; case 3: olddos = 0; wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, cnp->cn_namelen, pmp) + 1; break; } if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) { wincnt = 1; olddos = 1; } unlen = winLenFixup(cnp->cn_nameptr, cnp->cn_namelen); /* * Suppress search for slots unless creating * file and at end of pathname, in which case * we watch for a place to put the new file in * case it doesn't already exist. */ slotcount = wincnt; if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) slotcount = 0; #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): dos version of filename %s, length %ld\n", dosfilename, cnp->cn_namelen); #endif /* * Search the directory pointed at by vdp for the name pointed at * by cnp->cn_nameptr. */ tdp = NULL; mbnambuf_init(&nb); /* * The outer loop ranges over the clusters that make up the * directory. Note that the root directory is different from all * other directories. It has a fixed number of blocks that are not * part of the pool of allocatable clusters. So, we treat it a * little differently. The root directory starts at "cluster" 0. */ diroff = 0; for (frcn = 0;; frcn++) { error = pcbmap(dp, frcn, &bn, &cluster, &blsize); if (error) { if (error == E2BIG) break; return (error); } error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); if (error) { return (error); } for (blkoff = 0; blkoff < blsize; blkoff += sizeof(struct direntry), diroff += sizeof(struct direntry)) { dep = (struct direntry *)(bp->b_data + blkoff); /* * If the slot is empty and we are still looking * for an empty then remember this one. If the * slot is not empty then check to see if it * matches what we are looking for. If the slot * has never been filled with anything, then the * remainder of the directory has never been used, * so there is no point in searching it. */ if (dep->deName[0] == SLOT_EMPTY || dep->deName[0] == SLOT_DELETED) { /* * Drop memory of previous long matches */ chksum = -1; mbnambuf_init(&nb); if (slotcount < wincnt) { slotcount++; slotoffset = diroff; } if (dep->deName[0] == SLOT_EMPTY) { brelse(bp); goto notfound; } } else { /* * If there wasn't enough space for our winentries, * forget about the empty space */ if (slotcount < wincnt) slotcount = 0; /* * Check for Win95 long filename entry */ if (dep->deAttributes == ATTR_WIN95) { if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) continue; chksum = win2unixfn(&nb, (struct winentry *)dep, chksum, pmp); continue; } chksum = winChkName(&nb, (const u_char *)cnp->cn_nameptr, unlen, chksum, pmp); if (chksum == -2) { chksum = -1; continue; } /* * Ignore volume labels (anywhere, not just * the root directory). */ if (dep->deAttributes & ATTR_VOLUME) { chksum = -1; continue; } /* * Check for a checksum or name match */ chksum_ok = (chksum == winChksum(dep->deName)); if (!chksum_ok && (!olddos || bcmp(dosfilename, dep->deName, 11))) { chksum = -1; continue; } #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): match blkoff %lu, diroff %d\n", blkoff, diroff); #endif /* * Remember where this directory * entry came from for whoever did * this lookup. */ dp->de_fndoffset = diroff; if (chksum_ok && nameiop == RENAME) { /* * Target had correct long name * directory entries, reuse them * as needed. */ dp->de_fndcnt = wincnt - 1; } else { /* * Long name directory entries * not present or corrupt, can only * reuse dos directory entry. */ dp->de_fndcnt = 0; } goto found; } } /* for (blkoff = 0; .... */ /* * Release the buffer holding the directory cluster just * searched. */ brelse(bp); } /* for (frcn = 0; ; frcn++) */ notfound: /* * We hold no disk buffers at this point. */ /* * Fixup the slot description to point to the place where * we might put the new DOS direntry (putting the Win95 * long name entries before that) */ if (!slotcount) { slotcount = 1; slotoffset = diroff; } if (wincnt > slotcount) slotoffset += sizeof(struct direntry) * (wincnt - slotcount); /* * If we get here we didn't find the entry we were looking for. But * that's ok if we are creating or renaming and are at the end of * the pathname and the directory hasn't been removed. */ #ifdef MSDOSFS_DEBUG printf("msdosfs_lookup(): op %d, refcnt %ld\n", nameiop, dp->de_refcnt); printf(" slotcount %d, slotoffset %d\n", slotcount, slotoffset); #endif if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN) && dp->de_refcnt != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. */ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, curthread); if (error) return (error); /* * Return an indication of where the new directory * entry should be put. */ dp->de_fndoffset = slotoffset; dp->de_fndcnt = wincnt - 1; /* * We return with the directory locked, so that * the parameters we set up above will still be * valid if we actually decide to do a direnter(). * We return ni_vp == NULL to indicate that the entry * does not currently exist; we leave a pointer to * the (locked) directory inode in ndp->ni_dvp. * * NB - if the directory is unlocked, then this * information cannot be used. */ return (EJUSTRETURN); } #if 0 /* * Insert name into cache (as non-existent) if appropriate. * * XXX Negative caching is broken for msdosfs because the name * cache doesn't understand peculiarities such as case insensitivity * and 8.3 filenames. Hence, it may not invalidate all negative * entries if a file with this name is later created. */ if ((cnp->cn_flags & MAKEENTRY) != 0) cache_enter(vdp, *vpp, cnp); #endif return (ENOENT); found: /* * NOTE: We still have the buffer with matched directory entry at * this point. */ isadir = dep->deAttributes & ATTR_DIRECTORY; scn = getushort(dep->deStartCluster); if (FAT32(pmp)) { scn |= getushort(dep->deHighClust) << 16; if (scn == pmp->pm_rootdirblk) { /* * There should actually be 0 here. * Just ignore the error. */ scn = MSDOSFSROOT; } } if (isadir) { cluster = scn; if (cluster == MSDOSFSROOT) blkoff = MSDOSFSROOT_OFS; else blkoff = 0; } else if (cluster == MSDOSFSROOT) blkoff = diroff; /* * Now release buf to allow deget to read the entry again. * Reserving it here and giving it to deget could result * in a deadlock. */ brelse(bp); bp = NULL; foundroot: /* * If we entered at foundroot, then we are looking for the . or .. * entry of the filesystems root directory. isadir and scn were * setup before jumping here. And, bp is already null. */ if (FAT32(pmp) && scn == MSDOSFSROOT) scn = pmp->pm_rootdirblk; if (scnp != NULL) { *scnp = cluster; *blkoffp = blkoff; return (0); } /* * If deleting, and at end of pathname, return * parameters which can be used to remove file. */ if (nameiop == DELETE && (flags & ISLASTCN)) { /* * Don't allow deleting the root. */ if (blkoff == MSDOSFSROOT_OFS) return (EBUSY); /* * Write access to directory required to delete files. */ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, curthread); if (error) return (error); /* * Return pointer to current entry in dp->i_offset. * Save directory inode pointer in ndp->ni_dvp for dirremove(). */ if (dp->de_StartCluster == scn && isadir) { /* "." */ - VREF(vdp); + vref(vdp); *vpp = vdp; return (0); } error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE, &tdp); if (error) return (error); return (msdosfs_lookup_checker(pmp, vdp, tdp, vpp)); } /* * If rewriting (RENAME), return the inode and the * information required to rewrite the present directory * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ if (nameiop == RENAME && (flags & ISLASTCN)) { if (blkoff == MSDOSFSROOT_OFS) return (EBUSY); error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, curthread); if (error) return (error); /* * Careful about locking second inode. * This can only occur if the target is ".". */ if (dp->de_StartCluster == scn && isadir) return (EISDIR); if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE, &tdp)) != 0) return (error); if ((error = msdosfs_lookup_checker(pmp, vdp, tdp, vpp)) != 0) return (error); return (0); } /* * Step through the translation in the name. We do not `vput' the * directory because we may need it again if a symbolic link * is relative to the current directory. Instead we save it * unlocked as "pdp". We must get the target inode before unlocking * the directory to insure that the inode will not be removed * before we get it. We prevent deadlock by always fetching * inodes from the root, moving down the directory tree. Thus * when following backward pointers ".." we must unlock the * parent directory before getting the requested directory. */ pdp = vdp; if (flags & ISDOTDOT) { dd_arg.cluster = cluster; dd_arg.blkoff = blkoff; error = vn_vget_ino_gen(vdp, msdosfs_deget_dotdot, &dd_arg, cnp->cn_lkflags, vpp); if (error != 0) { *vpp = NULL; return (error); } /* * Recheck that ".." still points to the inode we * looked up before pdp lock was dropped. */ error = msdosfs_lookup_ino(pdp, NULL, cnp, &scn, &blkoff); if (error) { vput(*vpp); *vpp = NULL; return (error); } if (FAT32(pmp) && scn == MSDOSFSROOT) scn = pmp->pm_rootdirblk; inode1 = DETOI(pmp, scn, blkoff); if (VTODE(*vpp)->de_inode != inode1) { vput(*vpp); goto restart; } error = msdosfs_lookup_checker(pmp, vdp, VTODE(*vpp), vpp); if (error != 0) return (error); } else if (dp->de_StartCluster == scn && isadir) { if (cnp->cn_namelen != 1 || cnp->cn_nameptr[0] != '.') { /* fs is corrupted, non-dot lookup returned dvp */ msdosfs_integrity_error(pmp); return (EBADF); } - VREF(vdp); /* we want ourself, ie "." */ + vref(vdp); /* we want ourself, ie "." */ *vpp = vdp; } else { if ((error = deget(pmp, cluster, blkoff, LK_EXCLUSIVE, &tdp)) != 0) return (error); if ((error = msdosfs_lookup_checker(pmp, vdp, tdp, vpp)) != 0) return (error); } /* * Insert name into cache if appropriate. */ if (cnp->cn_flags & MAKEENTRY) cache_enter(vdp, *vpp, cnp); return (0); } /* * dep - directory entry to copy into the directory * ddep - directory to add to * depp - return the address of the denode for the created directory entry * if depp != 0 * cnp - componentname needed for Win95 long filenames */ int createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp) { int error; u_long dirclust, diroffset; struct direntry *ndep; struct msdosfsmount *pmp = ddep->de_pmp; struct buf *bp; daddr_t bn; int blsize; #ifdef MSDOSFS_DEBUG printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", dep, ddep, depp, cnp); #endif /* * If no space left in the directory then allocate another cluster * and chain it onto the end of the file. There is one exception * to this. That is, if the root directory has no more space it * can NOT be expanded. extendfile() checks for and fails attempts * to extend the root directory. We just return an error in that * case. */ if (ddep->de_fndoffset >= ddep->de_FileSize) { diroffset = ddep->de_fndoffset + sizeof(struct direntry) - ddep->de_FileSize; dirclust = de_clcount(pmp, diroffset); error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR); if (error) { (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED); return error; } /* * Update the size of the directory */ ddep->de_FileSize += de_cn2off(pmp, dirclust); } /* * We just read in the cluster with space. Copy the new directory * entry in. Then write it to disk. NOTE: DOS directories * do not get smaller as clusters are emptied. */ error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), &bn, &dirclust, &blsize); if (error) return error; diroffset = ddep->de_fndoffset; if (dirclust != MSDOSFSROOT) diroffset &= pmp->pm_crbomask; if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) { brelse(bp); return error; } ndep = bptoep(pmp, bp, ddep->de_fndoffset); rootde_alloced(ddep); DE_EXTERNALIZE(ndep, dep); /* * Now write the Win95 long name */ if (ddep->de_fndcnt > 0) { uint8_t chksum = winChksum(ndep->deName); const u_char *un = (const u_char *)cnp->cn_nameptr; int unlen = cnp->cn_namelen; int cnt = 1; while (--ddep->de_fndcnt >= 0) { if (!(ddep->de_fndoffset & pmp->pm_crbomask)) { if (DOINGASYNC(DETOV(ddep))) bdwrite(bp); else if ((error = bwrite(bp)) != 0) return error; ddep->de_fndoffset -= sizeof(struct direntry); error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), &bn, 0, &blsize); if (error) return error; error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); if (error) { return error; } ndep = bptoep(pmp, bp, ddep->de_fndoffset); } else { ndep--; ddep->de_fndoffset -= sizeof(struct direntry); } rootde_alloced(ddep); if (!unix2winfn(un, unlen, (struct winentry *)ndep, cnt++, chksum, pmp)) break; } } if (DOINGASYNC(DETOV(ddep))) bdwrite(bp); else if ((error = bwrite(bp)) != 0) return error; /* * If they want us to return with the denode gotten. */ if (depp) { if (dep->de_Attributes & ATTR_DIRECTORY) { dirclust = dep->de_StartCluster; if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) dirclust = MSDOSFSROOT; if (dirclust == MSDOSFSROOT) diroffset = MSDOSFSROOT_OFS; else diroffset = 0; } return (deget(pmp, dirclust, diroffset, LK_EXCLUSIVE, depp)); } return 0; } /* * Be sure a directory is empty except for "." and "..". Return 1 if empty, * return 0 if not empty or error. */ int dosdirempty(struct denode *dep) { int blsize; int error; u_long cn; daddr_t bn; struct buf *bp; struct msdosfsmount *pmp = dep->de_pmp; struct direntry *dentp; /* * Since the filesize field in directory entries for a directory is * zero, we just have to feel our way through the directory until * we hit end of file. */ for (cn = 0;; cn++) { if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { if (error == E2BIG) return (1); /* it's empty */ return (0); } error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); if (error) { return (0); } for (dentp = (struct direntry *)bp->b_data; (char *)dentp < bp->b_data + blsize; dentp++) { if (dentp->deName[0] != SLOT_DELETED && (dentp->deAttributes & ATTR_VOLUME) == 0) { /* * In dos directories an entry whose name * starts with SLOT_EMPTY (0) starts the * beginning of the unused part of the * directory, so we can just return that it * is empty. */ if (dentp->deName[0] == SLOT_EMPTY) { brelse(bp); return (1); } /* * Any names other than "." and ".." in a * directory mean it is not empty. */ if (bcmp(dentp->deName, ". ", 11) && bcmp(dentp->deName, ".. ", 11)) { brelse(bp); #ifdef MSDOSFS_DEBUG printf("dosdirempty(): entry found %02x, %02x\n", dentp->deName[0], dentp->deName[1]); #endif return (0); /* not empty */ } } } brelse(bp); } /* NOTREACHED */ } /* * Check to see if the directory described by target is in some * subdirectory of source. This prevents something like the following from * succeeding and leaving a bunch or files and directories orphaned. mv * /a/b/c /a/b/c/d/e/f Where c and f are directories. * * source - the inode for /a/b/c * target - the inode for /a/b/c/d/e/f * * Returns 0 if target is NOT a subdirectory of source. * Otherwise returns a non-zero error number. */ int doscheckpath(struct denode *source, struct denode *target, daddr_t *wait_scn) { daddr_t scn; struct msdosfsmount *pmp; struct direntry *ep; struct denode *dep; struct buf *bp = NULL; int error = 0; *wait_scn = 0; pmp = target->de_pmp; KASSERT(pmp == source->de_pmp, ("doscheckpath: source and target on different filesystems")); if ((target->de_Attributes & ATTR_DIRECTORY) == 0 || (source->de_Attributes & ATTR_DIRECTORY) == 0) return (ENOTDIR); if (target->de_StartCluster == source->de_StartCluster) return (EEXIST); if (target->de_StartCluster == MSDOSFSROOT || (FAT32(pmp) && target->de_StartCluster == pmp->pm_rootdirblk)) return (0); dep = target; vget(DETOV(dep), LK_EXCLUSIVE); for (;;) { if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { error = ENOTDIR; break; } scn = dep->de_StartCluster; error = bread(pmp->pm_devvp, cntobn(pmp, scn), pmp->pm_bpcluster, NOCRED, &bp); if (error != 0) break; ep = (struct direntry *)bp->b_data + 1; if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || bcmp(ep->deName, ".. ", 11) != 0) { error = ENOTDIR; brelse(bp); break; } scn = getushort(ep->deStartCluster); if (FAT32(pmp)) scn |= getushort(ep->deHighClust) << 16; brelse(bp); if (scn == source->de_StartCluster) { error = EINVAL; break; } if (scn == MSDOSFSROOT) break; if (FAT32(pmp) && scn == pmp->pm_rootdirblk) { /* * scn should be 0 in this case, * but we silently ignore the error. */ break; } vput(DETOV(dep)); dep = NULL; /* NOTE: deget() clears dep on error */ error = deget(pmp, scn, 0, LK_EXCLUSIVE | LK_NOWAIT, &dep); if (error != 0) { *wait_scn = scn; break; } } #ifdef MSDOSFS_DEBUG if (error == ENOTDIR) printf("doscheckpath(): .. not a directory?\n"); #endif if (dep != NULL) vput(DETOV(dep)); return (error); } /* * Read in the disk block containing the directory entry (dirclu, dirofs) * and return the address of the buf header, and the address of the * directory entry within the block. */ int readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct buf **bpp, struct direntry **epp) { int error; daddr_t bn; int blsize; blsize = pmp->pm_bpcluster; if (dirclust == MSDOSFSROOT && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; bn = detobn(pmp, dirclust, diroffset); if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) { brelse(*bpp); *bpp = NULL; return (error); } if (epp) *epp = bptoep(pmp, *bpp, diroffset); return (0); } /* * Read in the disk block containing the directory entry dep came from and * return the address of the buf header, and the address of the directory * entry within the block. */ int readde(struct denode *dep, struct buf **bpp, struct direntry **epp) { return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, bpp, epp)); } /* * Remove a directory entry. At this point the file represented by the * directory entry to be removed is still full length until no one has it * open. When the file no longer being used msdosfs_inactive() is called * and will truncate the file to 0 length. When the vnode containing the * denode is needed for some other purpose by VFS it will call * msdosfs_reclaim() which will remove the denode from the denode cache. * * pdep directory where the entry is removed * dep file to be removed */ int removede(struct denode *pdep, struct denode *dep) { int error; struct direntry *ep; struct buf *bp; daddr_t bn; int blsize; struct msdosfsmount *pmp = pdep->de_pmp; u_long offset = pdep->de_fndoffset; #ifdef MSDOSFS_DEBUG printf("removede(): filename %s, dep %p, offset %08lx\n", dep->de_Name, dep, offset); #endif dep->de_refcnt--; offset += sizeof(struct direntry); do { offset -= sizeof(struct direntry); error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize); if (error) return error; error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); if (error) { return error; } ep = bptoep(pmp, bp, offset); /* * Check whether, if we came here the second time, i.e. * when underflowing into the previous block, the last * entry in this block is a longfilename entry, too. */ if (ep->deAttributes != ATTR_WIN95 && offset != pdep->de_fndoffset) { brelse(bp); break; } offset += sizeof(struct direntry); while (1) { /* * We are a bit aggressive here in that we delete any Win95 * entries preceding this entry, not just the ones we "own". * Since these presumably aren't valid anyway, * there should be no harm. */ offset -= sizeof(struct direntry); ep--->deName[0] = SLOT_DELETED; rootde_freed(pdep); if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) || !(offset & pmp->pm_crbomask) || ep->deAttributes != ATTR_WIN95) break; } if (DOINGASYNC(DETOV(pdep))) bdwrite(bp); else if ((error = bwrite(bp)) != 0) return error; } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95) && !(offset & pmp->pm_crbomask) && offset); return 0; } /* * Create a unique DOS name in dvp */ int uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp) { struct msdosfsmount *pmp = dep->de_pmp; struct direntry *dentp; int gen; int blsize; u_long cn; daddr_t bn; struct buf *bp; int error; if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp, cnp->cn_namelen, 0, pmp) ? 0 : EINVAL); for (gen = 1;; gen++) { /* * Generate DOS name with generation number */ if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, cnp->cn_namelen, gen, pmp)) return gen == 1 ? EINVAL : EEXIST; /* * Now look for a dir entry with this exact name */ for (cn = error = 0; !error; cn++) { if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { if (error == E2BIG) /* EOF reached and not found */ return 0; return error; } error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); if (error) { return error; } for (dentp = (struct direntry *)bp->b_data; (char *)dentp < bp->b_data + blsize; dentp++) { if (dentp->deName[0] == SLOT_EMPTY) { /* * Last used entry and not found */ brelse(bp); return 0; } /* * Ignore volume labels and Win95 entries */ if (dentp->deAttributes & ATTR_VOLUME) continue; if (!bcmp(dentp->deName, cp, 11)) { error = EEXIST; break; } } brelse(bp); } } } diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 6c2e35713287..ad9404a18fc8 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -1,9948 +1,9948 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 /* * Rpc op calls, generally called from the vnode op calls or through the * buffer cache, for NFS v2, 3 and 4. * These do not normally make any changes to vnode arguments or use * structures that might change between the VFS variants. The returned * arguments are all at the end, after the NFSPROC_T *p one. */ #include "opt_inet6.h" #include #include #include #include #include SYSCTL_DECL(_vfs_nfs); static int nfsignore_eexist = 0; SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW, &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink"); static int nfscl_dssameconn = 0; SYSCTL_INT(_vfs_nfs, OID_AUTO, dssameconn, CTLFLAG_RW, &nfscl_dssameconn, 0, "Use same TCP connection to multiple DSs"); static uint64_t nfs_maxcopyrange = SSIZE_MAX; SYSCTL_U64(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW, &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable"); /* * Global variables */ extern struct nfsstatsv1 nfsstatsv1; extern int nfs_numnfscbd; extern struct timeval nfsboottime; extern u_int32_t newnfs_false, newnfs_true; extern nfstype nfsv34_type[9]; extern int nfsrv_useacl; extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; extern int nfscl_debuglevel; extern int nfs_pnfsiothreads; extern u_long sb_max_adj; NFSCLSTATEMUTEX; int nfstest_outofseq = 0; int nfscl_assumeposixlocks = 1; int nfscl_enablecallb = 0; short nfsv4_cbport = NFSV4_CBPORT; int nfstest_openallsetattr = 0; #define DIRHDSIZ offsetof(struct dirent, d_name) /* * nfscl_getsameserver() can return one of three values: * NFSDSP_USETHISSESSION - Use this session for the DS. * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new * session. * NFSDSP_NOTFOUND - No matching server was found. */ enum nfsclds_state { NFSDSP_USETHISSESSION = 0, NFSDSP_SEQTHISSESSION = 1, NFSDSP_NOTFOUND = 2, }; /* * Do a write RPC on a DS data file, using this structure for the arguments, * so that this function can be executed by a separate kernel process. */ struct nfsclwritedsdorpc { int done; int inprog; struct task tsk; struct vnode *vp; int iomode; int must_commit; nfsv4stateid_t *stateidp; struct nfsclds *dsp; uint64_t off; int len; #ifdef notyet int advise; #endif struct nfsfh *fhp; struct mbuf *m; int vers; int minorvers; struct ucred *cred; NFSPROC_T *p; int err; }; static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *, struct ucred *, NFSPROC_T *, struct nfsvattr *, int *); static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *); static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *, struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, int); static int nfsrpc_deallocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *, struct nfsvattr *, int *, struct ucred *, NFSPROC_T *); static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *, nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, int *); static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *, nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, int *, int *); static bool nfscl_invalidfname(bool, char *, int); static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, struct nfscllockowner *, u_int64_t, u_int64_t, u_int32_t, struct ucred *, NFSPROC_T *, int); static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, struct acl *, nfsv4stateid_t *); static int nfsrpc_layouterror(struct nfsmount *, uint8_t *, int, uint64_t, uint64_t, nfsv4stateid_t *, struct ucred *, NFSPROC_T *, uint32_t, uint32_t, char *); static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int, uint32_t, uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **, struct ucred *, NFSPROC_T *); static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *, struct sockaddr_in6 *, sa_family_t, int, int, struct nfsclds **, NFSPROC_T *); static void nfscl_initsessionslots(struct nfsclsession *); static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *, nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *, struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *, NFSPROC_T *); static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *, nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *, struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *, struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *); static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *, struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int, struct ucred *, NFSPROC_T *); static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *, nfsv4stateid_t *, struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *); static int nfsio_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *, struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int, struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *); static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *, struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int, struct ucred *, NFSPROC_T *); static enum nfsclds_state nfscl_getsameserver(struct nfsmount *, struct nfsclds *, struct nfsclds **, uint32_t *); static int nfsio_commitds(vnode_t, uint64_t, int, struct nfsclds *, struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *); static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *, struct nfsfh *, int, int, struct ucred *, NFSPROC_T *); #ifdef notyet static int nfsio_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *, struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *); static int nfsrpc_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *, struct nfsfh *, int, int, struct ucred *, NFSPROC_T *); #endif static int nfsrpc_allocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *, struct nfsvattr *, int *, struct ucred *, NFSPROC_T *); static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t, uint64_t, uint64_t, nfsv4stateid_t *, int, int, int); static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *, NFSPROC_T *); static int nfsrv_parselayoutget(struct nfsmount *, struct nfsrv_descript *, nfsv4stateid_t *, int *, struct nfsclflayouthead *); static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *, int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, struct nfscldeleg **, struct ucred *, NFSPROC_T *); static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *, nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, int *, int *); static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *, int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, struct nfscldeleg **, nfsv4stateid_t *, int, int, int, int *, struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *); static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *, nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, int *, int *, nfsv4stateid_t *, int, int, int, int *, struct nfsclflayouthead *, int *); static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t, uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *, struct nfsclflayouthead *, struct ucred *, NFSPROC_T *); static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *, int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **, struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_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); static void nfscl_statfs(struct vnode *, struct ucred *, NFSPROC_T *); int nfs_pnfsio(task_fn_t *, void *); /* * nfs null call from vfs. */ int nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p) { int error; struct nfsrv_descript nfsd, *nd = &nfsd; NFSCL_REQSTART(nd, NFSPROC_NULL, vp, NULL); error = nfscl_request(nd, vp, p, cred); if (nd->nd_repstat && !error) error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * nfs access rpc op. * For nfs version 3 and 4, use the access rpc to check accessibility. If file * modes are changed on the server, accesses might still fail later. */ int nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) { int error; u_int32_t mode, rmode; if (acmode & VREAD) mode = NFSACCESS_READ; else mode = 0; if (vp->v_type == VDIR) { if (acmode & VWRITE) mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE); if (acmode & VEXEC) mode |= NFSACCESS_LOOKUP; } else { if (acmode & VWRITE) mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); if (acmode & VEXEC) mode |= NFSACCESS_EXECUTE; } /* * Now, just call nfsrpc_accessrpc() to do the actual RPC. */ error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode); /* * The NFS V3 spec does not clarify whether or not * the returned access bits can be a superset of * the ones requested, so... */ if (!error && (rmode & mode) != mode) error = EACCES; return (error); } /* * The actual rpc, separated out for Darwin. */ int nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep) { u_int32_t *tl; u_int32_t supported, rmode; int error; struct nfsrv_descript nfsd, *nd = &nfsd; nfsattrbit_t attrbits; struct nfsmount *nmp; struct nfsnode *np; *attrflagp = 0; supported = mode; nmp = VFSTONFS(vp->v_mount); np = VTONFS(vp); if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 && nmp->nm_fhsize == 0) { /* Attempt to get the actual root file handle. */ error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, p); if (error != 0) return (EACCES); if (np->n_fhp->nfh_len == NFSX_FHMAX + 1) nfscl_statfs(vp, cred, p); } NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp, cred); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(mode); if (nd->nd_flag & ND_NFSV4) { /* * And do a Getattr op. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); (void) nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (nd->nd_flag & ND_NFSV3) { error = nfscl_postop_attr(nd, nap, attrflagp); if (error) goto nfsmout; } if (!nd->nd_repstat) { if (nd->nd_flag & ND_NFSV4) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); supported = fxdr_unsigned(u_int32_t, *tl++); } else { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); } rmode = fxdr_unsigned(u_int32_t, *tl); if (nd->nd_flag & ND_NFSV4) error = nfscl_postop_attr(nd, nap, attrflagp); /* * It's not obvious what should be done about * unsupported access modes. For now, be paranoid * and clear the unsupported ones. */ rmode &= supported; *rmodep = rmode; } else error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * nfs open rpc */ int nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) { struct nfsclopen *op; struct nfscldeleg *dp; struct nfsfh *nfhp; struct nfsnode *np = VTONFS(vp); struct nfsmount *nmp = VFSTONFS(vp->v_mount); u_int32_t mode, clidrev; int ret, newone, error, expireret = 0, retrycnt; /* * For NFSv4, Open Ops are only done on Regular Files. */ if (vp->v_type != VREG) return (0); mode = 0; if (amode & FREAD) mode |= NFSV4OPEN_ACCESSREAD; if (amode & FWRITE) mode |= NFSV4OPEN_ACCESSWRITE; if (NFSHASNFSV4N(nmp)) { if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && (vn_irflag_read(vp) & VIRF_NAMEDATTR) == 0) { if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) mode |= NFSV4OPEN_WANTWRITEDELEG; else mode |= NFSV4OPEN_WANTANYDELEG; } else mode |= NFSV4OPEN_WANTNODELEG; } nfhp = np->n_fhp; retrycnt = 0; do { dp = NULL; error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, (mode & NFSV4OPEN_ACCESSBOTH), 1, cred, p, NULL, &op, &newone, &ret, 1, true); if (error) { return (error); } if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; else clidrev = 0; if (ret == NFSCLOPEN_DOOPEN) { if (np->n_v4 != NULL) { /* * For the first attempt, try and get a layout, if * pNFS is enabled for the mount. */ if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0) error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data, np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, mode, op, NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp, 0, 0x0, cred, p, 0, 0); else error = nfsrpc_getopenlayout(nmp, vp, np->n_v4->n4_data, np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, mode, op, NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp, cred, p); if (dp != NULL) { NFSLOCKNODE(np); np->n_flag &= ~NDELEGMOD; /* * Invalidate the attribute cache, so that * attributes that pre-date the issue of a * delegation are not cached, since the * cached attributes will remain valid while * the delegation is held. */ NFSINVALATTRCACHE(np); NFSUNLOCKNODE(np); (void) nfscl_deleg(nmp->nm_mountp, op->nfso_own->nfsow_clp, nfhp->nfh_fh, nfhp->nfh_len, cred, p, dp); } } else if (NFSHASNFSV4N(nmp)) { /* * For the first attempt, try and get a layout, if * pNFS is enabled for the mount. */ if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0) error = nfsrpc_openrpc(nmp, vp, nfhp->nfh_fh, nfhp->nfh_len, nfhp->nfh_fh, nfhp->nfh_len, mode, op, NULL, 0, &dp, 0, 0x0, cred, p, 0, 0); else error = nfsrpc_getopenlayout(nmp, vp, nfhp->nfh_fh, nfhp->nfh_len, nfhp->nfh_fh, nfhp->nfh_len, mode, op, NULL, 0, &dp, cred, p); if (dp != NULL) { NFSLOCKNODE(np); np->n_flag &= ~NDELEGMOD; /* * Invalidate the attribute cache, so that * attributes that pre-date the issue of a * delegation are not cached, since the * cached attributes will remain valid while * the delegation is held. */ NFSINVALATTRCACHE(np); NFSUNLOCKNODE(np); (void) nfscl_deleg(nmp->nm_mountp, op->nfso_own->nfsow_clp, nfhp->nfh_fh, nfhp->nfh_len, cred, p, dp); } } else { error = EIO; } newnfs_copyincred(cred, &op->nfso_cred); } else if (ret == NFSCLOPEN_SETCRED) /* * This is a new local open on a delegation. It needs * to have credentials so that an open can be done * against the server during recovery. */ newnfs_copyincred(cred, &op->nfso_cred); /* * nfso_opencnt is the count of how many VOP_OPEN()s have * been done on this Open successfully and a VOP_CLOSE() * is expected for each of these. * If error is non-zero, don't increment it, since the Open * hasn't succeeded yet. */ if (!error) { op->nfso_opencnt++; if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp)) { NFSLOCKNODE(np); np->n_openstateid = op; NFSUNLOCKNODE(np); } } nfscl_openrelease(nmp, op, error, newone); if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || error == NFSERR_BADSESSION) { (void) nfs_catnap(PZERO, error, "nfs_open"); } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && clidrev != 0) { expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); retrycnt++; } } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || error == NFSERR_BADSESSION || ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && expireret == 0 && clidrev != 0 && retrycnt < 4)); if (error && retrycnt >= 4) error = EIO; return (error); } /* * the actual open rpc */ int nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, u_int8_t *name, int namelen, struct nfscldeleg **dpp, int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p, int syscred, int recursed) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfscldeleg *dp, *ndp = NULL; struct nfsvattr nfsva; u_int32_t rflags, deleg; nfsattrbit_t attrbits; int error, ret, acesize, limitby; struct nfsclsession *tsep; dp = *dpp; *dpp = NULL; nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); *tl++ = txdr_unsigned(mode & (NFSV4OPEN_ACCESSBOTH | NFSV4OPEN_WANTDELEGMASK)); *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; *tl = tsep->nfsess_clientid.lval[1]; (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); if (reclaim) { *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(delegtype); } else { if (dp != NULL) { if (NFSHASNFSV4N(nmp)) *tl = txdr_unsigned( NFSV4OPEN_CLAIMDELEGATECURFH); else *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR); NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); if (NFSHASNFSV4N(nmp)) *tl++ = 0; else *tl++ = dp->nfsdl_stateid.seqid; *tl++ = dp->nfsdl_stateid.other[0]; *tl++ = dp->nfsdl_stateid.other[1]; *tl = dp->nfsdl_stateid.other[2]; if (!NFSHASNFSV4N(nmp)) (void)nfsm_strtom(nd, name, namelen); } else if (NFSHASNFSV4N(nmp)) { *tl = txdr_unsigned(NFSV4OPEN_CLAIMFH); } else { *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); (void)nfsm_strtom(nd, name, namelen); } } NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); (void) nfsrv_putattrbit(nd, &attrbits); if (syscred) nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error) return (error); NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); if (nd->nd_repstat == 0 || (nd->nd_repstat == NFSERR_DELAY && reclaim != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0)) { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); op->nfso_stateid.seqid = *tl++; op->nfso_stateid.other[0] = *tl++; op->nfso_stateid.other[1] = *tl++; op->nfso_stateid.other[2] = *tl; rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(u_int32_t, *tl); if (deleg == NFSV4OPEN_DELEGATEREAD || deleg == NFSV4OPEN_DELEGATEWRITE) { if (!(op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_FIRSTDELEG)) op->nfso_own->nfsow_clp->nfsc_flags |= (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); ndp = malloc( sizeof (struct nfscldeleg) + newfhlen, M_NFSCLDELEG, M_WAITOK); LIST_INIT(&ndp->nfsdl_owner); LIST_INIT(&ndp->nfsdl_lock); ndp->nfsdl_clp = op->nfso_own->nfsow_clp; ndp->nfsdl_fhlen = newfhlen; NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); newnfs_copyincred(cred, &ndp->nfsdl_cred); nfscl_lockinit(&ndp->nfsdl_rwlock); NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); ndp->nfsdl_stateid.seqid = *tl++; ndp->nfsdl_stateid.other[0] = *tl++; ndp->nfsdl_stateid.other[1] = *tl++; ndp->nfsdl_stateid.other[2] = *tl++; ret = fxdr_unsigned(int, *tl); if (deleg == NFSV4OPEN_DELEGATEWRITE) { ndp->nfsdl_flags = NFSCLDL_WRITE; /* * Indicates how much the file can grow. */ NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); limitby = fxdr_unsigned(int, *tl++); switch (limitby) { case NFSV4OPEN_LIMITSIZE: ndp->nfsdl_sizelimit = fxdr_hyper(tl); break; case NFSV4OPEN_LIMITBLOCKS: ndp->nfsdl_sizelimit = fxdr_unsigned(u_int64_t, *tl++); ndp->nfsdl_sizelimit *= fxdr_unsigned(u_int64_t, *tl); break; default: error = NFSERR_BADXDR; goto nfsmout; } } else { ndp->nfsdl_flags = NFSCLDL_READ; } if (ret) ndp->nfsdl_flags |= NFSCLDL_RECALL; error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false, &ret, &acesize, p); if (error) goto nfsmout; } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && NFSHASNFSV4N(nmp)) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(uint32_t, *tl); if (deleg == NFSV4OPEN_CONTENTION || deleg == NFSV4OPEN_RESOURCE) NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; } NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); /* If the 2nd element == NFS_OK, the Getattr succeeded. */ if (*++tl == 0) { KASSERT(nd->nd_repstat == 0, ("nfsrpc_openrpc: Getattr repstat")); error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, p, cred); if (error) goto nfsmout; } if (ndp != NULL) { if (reclaim != 0 && dp != NULL) { ndp->nfsdl_change = dp->nfsdl_change; ndp->nfsdl_modtime = dp->nfsdl_modtime; ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; } else if (nd->nd_repstat == 0) { ndp->nfsdl_change = nfsva.na_filerev; ndp->nfsdl_modtime = nfsva.na_mtime; ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; } else ndp->nfsdl_flags |= NFSCLDL_RECALL; } nd->nd_repstat = 0; if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) { do { ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op, cred, p); if (ret == NFSERR_DELAY) (void) nfs_catnap(PZERO, ret, "nfs_open"); } while (ret == NFSERR_DELAY); error = ret; } if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) || nfscl_assumeposixlocks) op->nfso_posixlock = 1; else op->nfso_posixlock = 0; /* * If the server is handing out delegations, but we didn't * get one because an OpenConfirm was required, try the * Open again, to get a delegation. This is a harmless no-op, * from a server's point of view. */ if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) && (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && !error && dp == NULL && ndp == NULL && !recursed) { do { ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, mode, op, name, namelen, &ndp, 0, 0x0, cred, p, syscred, 1); if (ret == NFSERR_DELAY) (void) nfs_catnap(PZERO, ret, "nfs_open2"); } while (ret == NFSERR_DELAY); if (ret) { if (ndp != NULL) { free(ndp, M_NFSCLDELEG); ndp = NULL; } if (ret == NFSERR_STALECLIENTID || ret == NFSERR_STALEDONTRECOVER || ret == NFSERR_BADSESSION) error = ret; } } } if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; if (error == NFSERR_STALECLIENTID) nfscl_initiate_recovery(op->nfso_own->nfsow_clp); nfsmout: if (!error) *dpp = ndp; else if (ndp != NULL) free(ndp, M_NFSCLDELEG); m_freem(nd->nd_mrep); return (error); } /* * open downgrade rpc */ int nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; int error; NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp, cred); NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); if (NFSHASNFSV4N(VFSTONFS(vp->v_mount))) *tl++ = 0; else *tl++ = op->nfso_stateid.seqid; *tl++ = op->nfso_stateid.other[0]; *tl++ = op->nfso_stateid.other[1]; *tl++ = op->nfso_stateid.other[2]; *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); error = nfscl_request(nd, vp, p, cred); if (error) return (error); NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); if (!nd->nd_repstat) { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); op->nfso_stateid.seqid = *tl++; op->nfso_stateid.other[0] = *tl++; op->nfso_stateid.other[1] = *tl++; op->nfso_stateid.other[2] = *tl; } if (nd->nd_repstat && error == 0) error = nd->nd_repstat; if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(op->nfso_own->nfsow_clp); nfsmout: m_freem(nd->nd_mrep); return (error); } /* * V4 Close operation. */ int nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p) { struct nfsclclient *clp; int error; if (vp->v_type != VREG) return (0); if (doclose) error = nfscl_doclose(vp, &clp, p); else { error = nfscl_getclose(vp, &clp); if (error == 0) nfscl_clientrelease(clp); } return (error); } /* * Close the open. */ int nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p, bool loop_on_delayed, bool freeop) { struct nfsrv_descript nfsd, *nd = &nfsd; struct nfscllockowner *lp, *nlp; struct nfscllock *lop, *nlop; struct ucred *tcred; u_int64_t off = 0, len = 0; u_int32_t type = NFSV4LOCKT_READ; int error, do_unlock, trycnt; bool own_not_null; tcred = newnfs_getcred(); newnfs_copycred(&op->nfso_cred, tcred); /* * (Theoretically this could be done in the same * compound as the close, but having multiple * sequenced Ops in the same compound might be * too scary for some servers.) */ if (op->nfso_posixlock) { off = 0; len = NFS64BITSSET; type = NFSV4LOCKT_READ; } /* * Since this function is only called from VOP_INACTIVE(), no * other thread will be manipulating this Open. As such, the * lock lists are not being changed by other threads, so it should * be safe to do this without locking. */ LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { do_unlock = 1; LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { if (op->nfso_posixlock == 0) { off = lop->nfslo_first; len = lop->nfslo_end - lop->nfslo_first; if (lop->nfslo_type == F_WRLCK) type = NFSV4LOCKT_WRITE; else type = NFSV4LOCKT_READ; } if (do_unlock) { trycnt = 0; do { error = nfsrpc_locku(nd, nmp, lp, off, len, type, tcred, p, 0); if ((nd->nd_repstat == NFSERR_GRACE || nd->nd_repstat == NFSERR_DELAY) && error == 0) (void) nfs_catnap(PZERO, (int)nd->nd_repstat, "nfs_close"); } while ((nd->nd_repstat == NFSERR_GRACE || nd->nd_repstat == NFSERR_DELAY) && error == 0 && trycnt++ < 5); if (op->nfso_posixlock) do_unlock = 0; } nfscl_freelock(lop, 0); } /* * Do a ReleaseLockOwner. * The lock owner name nfsl_owner may be used by other opens for * other files but the lock_owner4 name that nfsrpc_rellockown() * puts on the wire has the file handle for this file appended * to it, so it can be done now. */ (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh, lp->nfsl_open->nfso_fhlen, tcred, p); } /* * There could be other Opens for different files on the same * OpenOwner, so locking is required. */ own_not_null = false; if (op->nfso_own != NULL) { own_not_null = true; NFSLOCKCLSTATE(); nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR); NFSUNLOCKCLSTATE(); } do { error = nfscl_tryclose(op, tcred, nmp, p, loop_on_delayed); if (error == NFSERR_GRACE) (void) nfs_catnap(PZERO, error, "nfs_close"); } while (error == NFSERR_GRACE); if (own_not_null) { NFSLOCKCLSTATE(); nfscl_lockunlock(&op->nfso_own->nfsow_rwlock); } LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) nfscl_freelockowner(lp, 0); if (freeop && error != NFSERR_DELAY) nfscl_freeopen(op, 0, true); if (own_not_null) NFSUNLOCKCLSTATE(); NFSFREECRED(tcred); return (error); } /* * The actual Close RPC. */ int nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp, struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p, int syscred) { u_int32_t *tl; int error; nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh, op->nfso_fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); if (NFSHASNFSV4N(nmp)) { *tl++ = 0; *tl++ = 0; } else { *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); *tl++ = op->nfso_stateid.seqid; } *tl++ = op->nfso_stateid.other[0]; *tl++ = op->nfso_stateid.other[1]; *tl = op->nfso_stateid.other[2]; if (syscred) nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error) return (error); if (!NFSHASNFSV4N(nmp)) NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); if (nd->nd_repstat == 0) NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); error = nd->nd_repstat; if (!NFSHASNFSV4N(nmp) && error == NFSERR_STALESTATEID) nfscl_initiate_recovery(op->nfso_own->nfsow_clp); nfsmout: m_freem(nd->nd_mrep); return (error); } /* * V4 Open Confirm RPC. */ int nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen, struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp; int error; nmp = VFSTONFS(vp->v_mount); if (NFSHASNFSV4N(nmp)) return (0); /* No confirmation for NFSv4.1. */ nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL, 0, 0, NULL); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); *tl++ = op->nfso_stateid.seqid; *tl++ = op->nfso_stateid.other[0]; *tl++ = op->nfso_stateid.other[1]; *tl++ = op->nfso_stateid.other[2]; *tl = txdr_unsigned(op->nfso_own->nfsow_seqid); error = nfscl_request(nd, vp, p, cred); if (error) return (error); NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); if (!nd->nd_repstat) { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); op->nfso_stateid.seqid = *tl++; op->nfso_stateid.other[0] = *tl++; op->nfso_stateid.other[1] = *tl++; op->nfso_stateid.other[2] = *tl; } error = nd->nd_repstat; if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(op->nfso_own->nfsow_clp); nfsmout: m_freem(nd->nd_mrep); return (error); } /* * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs() * when a mount has just occurred and when the server replies NFSERR_EXPIRED. */ int nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim, bool *retokp, struct ucred *cred, NFSPROC_T *p) { u_int32_t *tl; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9]; u_short port; int error, isinet6 = 0, callblen; nfsquad_t confirm; static u_int32_t rev = 0; struct nfsclds *dsp, *odsp; struct in6_addr a6; struct nfsclsession *tsep; struct rpc_reconupcall recon; struct nfscl_reconarg *rcp; if (nfsboottime.tv_sec == 0) NFSSETBOOTTIME(nfsboottime); if (NFSHASNFSV4N(nmp)) { error = NFSERR_BADSESSION; odsp = dsp = NULL; if (retokp != NULL) { NFSLOCKMNT(nmp); odsp = TAILQ_FIRST(&nmp->nm_sess); NFSUNLOCKMNT(nmp); } if (odsp != NULL) { /* * When a session already exists, first try a * CreateSession with the extant ClientID. */ dsp = malloc(sizeof(struct nfsclds) + odsp->nfsclds_servownlen + 1, M_NFSCLDS, M_WAITOK | M_ZERO); dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; dsp->nfsclds_servownlen = odsp->nfsclds_servownlen; dsp->nfsclds_sess.nfsess_clientid = odsp->nfsclds_sess.nfsess_clientid; dsp->nfsclds_sess.nfsess_sequenceid = odsp->nfsclds_sess.nfsess_sequenceid + 1; dsp->nfsclds_flags = odsp->nfsclds_flags; if (dsp->nfsclds_servownlen > 0) memcpy(dsp->nfsclds_serverown, odsp->nfsclds_serverown, dsp->nfsclds_servownlen + 1); mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF); nfscl_initsessionslots(&dsp->nfsclds_sess); error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, &nmp->nm_sockreq, NULL, dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p); NFSCL_DEBUG(1, "create session for extant " "ClientID=%d\n", error); if (error != 0) { nfscl_freenfsclds(dsp); dsp = NULL; /* * If *retokp is true, return any error other * than NFSERR_STALECLIENTID, * NFSERR_BADSESSION or NFSERR_STALEDONTRECOVER * so that nfscl_recover() will not loop. */ if (*retokp) return (NFSERR_IO); } else *retokp = true; } else if (retokp != NULL && *retokp) return (NFSERR_IO); if (error != 0) { /* * Either there was no previous session or the * CreateSession attempt failed, so... * do an ExchangeID followed by the CreateSession. */ clp->nfsc_rev = rev++; error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, 0, NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p); NFSCL_DEBUG(1, "aft exch=%d\n", error); if (error == 0) error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, &nmp->nm_sockreq, NULL, dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p); NFSCL_DEBUG(1, "aft createsess=%d\n", error); } if (error == 0) { /* * If the session supports a backchannel, set up * the BindConnectionToSession call in the krpc * so that it is done on a reconnection. */ if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0) { rcp = mem_alloc(sizeof(*rcp)); rcp->minorvers = nmp->nm_minorvers; memcpy(rcp->sessionid, dsp->nfsclds_sess.nfsess_sessionid, NFSX_V4SESSIONID); recon.call = nfsrpc_bindconnsess; recon.arg = rcp; CLNT_CONTROL(nmp->nm_client, CLSET_RECONUPCALL, &recon); } NFSLOCKMNT(nmp); /* * The old sessions cannot be safely free'd * here, since they may still be used by * in-progress RPCs. */ tsep = NULL; if (TAILQ_FIRST(&nmp->nm_sess) != NULL) { /* * Mark the old session defunct. Needed * when called from nfscl_hasexpired(). */ tsep = NFSMNT_MDSSESSION(nmp); tsep->nfsess_defunct = 1; } TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list); /* * Wake up RPCs waiting for a slot on the * old session. These will then fail with * NFSERR_BADSESSION and be retried with the * new session by nfsv4_setsequence(). * Also wakeup() processes waiting for the * new session. */ if (tsep != NULL) wakeup(&tsep->nfsess_slots); wakeup(&nmp->nm_sess); NFSUNLOCKMNT(nmp); } else if (dsp != NULL) nfscl_freenfsclds(dsp); if (error == 0 && reclaim == 0) { error = nfsrpc_reclaimcomplete(nmp, cred, p); NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error); if (error == NFSERR_COMPLETEALREADY || error == NFSERR_NOTSUPP) /* Ignore this error. */ error = 0; } return (error); } else if (retokp != NULL && *retokp) return (NFSERR_IO); clp->nfsc_rev = rev++; /* * Allocate a single session structure for NFSv4.0, because some of * the fields are used by NFSv4.0 although it doesn't do a session. */ dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO); mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF); NFSLOCKMNT(nmp); TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list); tsep = NFSMNT_MDSSESSION(nmp); NFSUNLOCKMNT(nmp); nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL, 0, 0, NULL); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(nfsboottime.tv_sec); *tl = txdr_unsigned(clp->nfsc_rev); (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); /* * set up the callback address */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFS_CALLBCKPROG); callblen = strlen(nfsv4_callbackaddr); if (callblen == 0) cp = nfscl_getmyip(nmp, &a6, &isinet6); if (nfscl_enablecallb && nfs_numnfscbd > 0 && (callblen > 0 || cp != NULL)) { port = htons(nfsv4_cbport); cp2 = (u_int8_t *)&port; #ifdef INET6 if ((callblen > 0 && strchr(nfsv4_callbackaddr, ':')) || isinet6) { char ip6buf[INET6_ADDRSTRLEN], *ip6add; (void) nfsm_strtom(nd, "tcp6", 4); if (callblen == 0) { ip6_sprintf(ip6buf, (struct in6_addr *)cp); ip6add = ip6buf; } else { ip6add = nfsv4_callbackaddr; } snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d", ip6add, cp2[0], cp2[1]); } else #endif { (void) nfsm_strtom(nd, "tcp", 3); if (callblen == 0) snprintf(addr, INET6_ADDRSTRLEN + 9, "%d.%d.%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3], cp2[0], cp2[1]); else snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d", nfsv4_callbackaddr, cp2[0], cp2[1]); } (void) nfsm_strtom(nd, addr, strlen(addr)); } else { (void) nfsm_strtom(nd, "tcp", 3); (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11); } NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(clp->nfsc_cbident); nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); tsep->nfsess_clientid.lval[0] = *tl++; tsep->nfsess_clientid.lval[1] = *tl++; confirm.lval[0] = *tl++; confirm.lval[1] = *tl; m_freem(nd->nd_mrep); nd->nd_mrep = NULL; /* * and confirm it. */ nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL, NULL, 0, 0, NULL); NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); *tl++ = tsep->nfsess_clientid.lval[0]; *tl++ = tsep->nfsess_clientid.lval[1]; *tl++ = confirm.lval[0]; *tl = confirm.lval[1]; nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error) return (error); m_freem(nd->nd_mrep); nd->nd_mrep = NULL; } error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * nfs getattr call. */ int nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap) { struct nfsrv_descript nfsd, *nd = &nfsd; int error; nfsattrbit_t attrbits; struct nfsnode *np; struct nfsmount *nmp; nmp = VFSTONFS(vp->v_mount); np = VTONFS(vp); if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 && nmp->nm_fhsize == 0) { /* Attempt to get the actual root file handle. */ error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, p); if (error != 0) return (EACCES); if (np->n_fhp->nfh_len == NFSX_FHMAX + 1) nfscl_statfs(vp, cred, p); } NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred); if (nd->nd_flag & ND_NFSV4) { NFSGETATTR_ATTRBIT(&attrbits); (void) nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (!nd->nd_repstat) error = nfsm_loadattr(nd, nap); else error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * nfs getattr call with non-vnode arguments. */ int nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp, uint32_t *leasep) { struct nfsrv_descript nfsd, *nd = &nfsd; int error, vers = NFS_VER2; nfsattrbit_t attrbits; nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0, cred); if (nd->nd_flag & ND_NFSV4) { vers = NFS_VER4; NFSGETATTR_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); (void) nfsrv_putattrbit(nd, &attrbits); } else if (nd->nd_flag & ND_NFSV3) { vers = NFS_VER3; } if (syscred) nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, vers, NULL, 1, xidp, NULL); if (error) return (error); if (nd->nd_repstat == 0) { 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); else error = nfsm_loadattr(nd, nap); } else error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * Do an nfs setattr operation. */ int nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp) { int error, expireret = 0, openerr, retrycnt; u_int32_t clidrev = 0, mode; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsfh *nfhp; nfsv4stateid_t stateid; void *lckp; if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size)) mode = NFSV4OPEN_ACCESSWRITE; else mode = NFSV4OPEN_ACCESSREAD; retrycnt = 0; do { lckp = NULL; openerr = 1; if (NFSHASNFSV4(nmp)) { nfhp = VTONFS(vp)->n_fhp; error = nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp); if (error && vp->v_type == VREG && (mode == NFSV4OPEN_ACCESSWRITE || nfstest_openallsetattr)) { /* * No Open stateid, so try and open the file * now. */ if (mode == NFSV4OPEN_ACCESSWRITE) openerr = nfsrpc_open(vp, FWRITE, cred, p); else openerr = nfsrpc_open(vp, FREAD, cred, p); if (!openerr) (void) nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp); } } if (vap != NULL) error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p, rnap, attrflagp); else error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid); if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) { NFSLOCKMNT(nmp); nmp->nm_state |= NFSSTA_OPENMODE; NFSUNLOCKMNT(nmp); } if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) nfscl_lockderef(lckp); if (!openerr) (void) nfsrpc_close(vp, 0, p); 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_setattr"); } else if ((error == NFSERR_EXPIRED || ((!NFSHASINT(nmp) || !NFSHASNFSV4N(nmp)) && error == NFSERR_BADSTATEID)) && clidrev != 0) { expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp) && NFSHASNFSV4N(nmp)) { error = EIO; } retrycnt++; } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || error == NFSERR_BADSESSION || (error == NFSERR_OLDSTATEID && retrycnt < 20) || ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && expireret == 0 && clidrev != 0 && retrycnt < 4) || (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD && retrycnt < 4)); if (error && retrycnt >= 4) error = EIO; return (error); } static int nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; int error; nfsattrbit_t attrbits; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp, cred); if (nd->nd_flag & ND_NFSV4) nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); vap->va_type = vp->v_type; nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0); if (nd->nd_flag & ND_NFSV3) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = newnfs_false; } else if (nd->nd_flag & ND_NFSV4) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); (void) nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, NULL); if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error) error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error) error = nfscl_postop_attr(nd, rnap, attrflagp); m_freem(nd->nd_mrep); if (nd->nd_repstat && !error) error = nd->nd_repstat; return (error); } /* * nfs lookup rpc */ int nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap, struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, uint32_t openmode) { uint32_t deleg, rflags, *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp; struct nfsnode *np; struct nfsfh *nfhp; nfsattrbit_t attrbits; int error = 0, lookupp = 0, newone, ret, retop; uint8_t own[NFSV4CL_LOCKNAMELEN]; struct nfsclopen *op; struct nfscldeleg *ndp; nfsv4stateid_t stateid; *attrflagp = 0; *dattrflagp = 0; if (dvp->v_type != VDIR) return (ENOTDIR); nmp = VFSTONFS(dvp->v_mount); if (len > NFS_MAXNAMLEN) return (ENAMETOOLONG); if (NFSHASNFSV4(nmp) && len == 1 && name[0] == '.') { /* * Just return the current dir's fh. */ np = VTONFS(dvp); nfhp = malloc(sizeof (struct nfsfh) + np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); nfhp->nfh_len = np->n_fhp->nfh_len; NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); *nfhpp = nfhp; return (0); } if (NFSHASNFSV4(nmp) && len == 2 && name[0] == '.' && name[1] == '.') { lookupp = 1; openmode = 0; NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp, cred); } else if (openmode != 0) { NFSCL_REQSTART(nd, NFSPROC_LOOKUPOPEN, dvp, cred); nfsm_strtom(nd, name, len); } else { NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp, cred); (void) nfsm_strtom(nd, name, len); } if (nd->nd_flag & ND_NFSV4) { NFSGETATTR_ATTRBIT(&attrbits); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_GETFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); if (openmode != 0) { /* Test for a VREG file. */ NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_VERIFY); nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSX_UNSIGNED); *tl = vtonfsv34_type(VREG); /* Attempt the Open for VREG. */ nfscl_filllockowner(NULL, own, F_POSIX); NFSM_BUILD(tl, uint32_t *, 6 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_OPEN); *tl++ = 0; /* seqid, ignored. */ *tl++ = txdr_unsigned(openmode | NFSV4OPEN_WANTNODELEG); *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); *tl++ = 0; /* ClientID, ignored. */ *tl = 0; nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); *tl = txdr_unsigned(NFSV4OPEN_CLAIMFH); } } error = nfscl_request(nd, dvp, p, cred); if (error) return (error); ndp = NULL; if (nd->nd_repstat) { /* * When an NFSv4 Lookupp returns ENOENT, it means that * the lookup is at the root of an fs, so return this dir. */ if (nd->nd_repstat == NFSERR_NOENT && lookupp) { np = VTONFS(dvp); nfhp = malloc(sizeof (struct nfsfh) + np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); nfhp->nfh_len = np->n_fhp->nfh_len; NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); *nfhpp = nfhp; m_freem(nd->nd_mrep); return (0); } if (nd->nd_flag & ND_NFSV3) error = nfscl_postop_attr(nd, dnap, dattrflagp); else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { /* Load the directory attributes. */ error = nfsm_loadattr(nd, dnap); if (error != 0) goto nfsmout; *dattrflagp = 1; } /* Check Lookup operation reply status. */ if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*++tl != 0) goto nfsmout; } /* Look for GetFH reply. */ if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*++tl != 0) goto nfsmout; error = nfsm_getfh(nd, nfhpp); if (error) goto nfsmout; } /* Look for Getattr reply. */ if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*++tl != 0) goto nfsmout; error = nfsm_loadattr(nd, nap); if (error == 0) { /* * We have now successfully completed the * lookup, so set nd_repstat to 0. */ nd->nd_repstat = 0; *attrflagp = 1; } } goto nfsmout; } if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { /* Load the directory attributes. */ error = nfsm_loadattr(nd, dnap); if (error != 0) goto nfsmout; *dattrflagp = 1; /* Skip over the Lookup and GetFH operation status values. */ NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); } error = nfsm_getfh(nd, nfhpp); if (error) goto nfsmout; error = nfscl_postop_attr(nd, nap, attrflagp); if (openmode != 0 && error == 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 10 * NFSX_UNSIGNED); tl += 4; /* Skip over Verify+Open status. */ stateid.seqid = *tl++; stateid.other[0] = *tl++; stateid.other[1] = *tl++; stateid.other[2] = *tl; rflags = fxdr_unsigned(uint32_t, *(tl + 6)); error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error != 0) goto nfsmout; NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(uint32_t, *tl); if (deleg == NFSV4OPEN_DELEGATEREAD || deleg == NFSV4OPEN_DELEGATEWRITE) { /* * Just need to fill in the fields used by * nfscl_trydelegreturn(). * Mark the mount point as acquiring * delegations, so NFSPROC_LOOKUPOPEN will * no longer be done. */ NFSLOCKMNT(nmp); nmp->nm_privflag |= NFSMNTP_DELEGISSUED; NFSUNLOCKMNT(nmp); ndp = malloc(sizeof(struct nfscldeleg) + (*nfhpp)->nfh_len, M_NFSCLDELEG, M_WAITOK); ndp->nfsdl_fhlen = (*nfhpp)->nfh_len; NFSBCOPY((*nfhpp)->nfh_fh, ndp->nfsdl_fh, ndp->nfsdl_fhlen); newnfs_copyincred(cred, &ndp->nfsdl_cred); NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); ndp->nfsdl_stateid.seqid = *tl++; ndp->nfsdl_stateid.other[0] = *tl++; ndp->nfsdl_stateid.other[1] = *tl++; ndp->nfsdl_stateid.other[2] = *tl++; } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && NFSHASNFSV4N(nmp)) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(uint32_t, *tl); if (deleg == NFSV4OPEN_CONTENTION || deleg == NFSV4OPEN_RESOURCE) NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; } ret = nfscl_open(dvp, (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, openmode, 0, cred, p, NULL, &op, &newone, &retop, 1, true); if (ret != 0) goto nfsmout; if (newone != 0) { op->nfso_stateid.seqid = stateid.seqid; op->nfso_stateid.other[0] = stateid.other[0]; op->nfso_stateid.other[1] = stateid.other[1]; op->nfso_stateid.other[2] = stateid.other[2]; op->nfso_mode = openmode; } else { op->nfso_stateid.seqid = stateid.seqid; if (retop == NFSCLOPEN_DOOPEN) op->nfso_mode |= openmode; } if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || nfscl_assumeposixlocks) op->nfso_posixlock = 1; else op->nfso_posixlock = 0; nfscl_openrelease(nmp, op, 0, 0); if (ndp != NULL) { /* * Since we do not have the vnode, we * cannot invalidate cached attributes. * Just return the delegation. */ nfscl_trydelegreturn(ndp, cred, nmp, p); } } if ((nd->nd_flag & ND_NFSV3) && !error) error = nfscl_postop_attr(nd, dnap, dattrflagp); nfsmout: m_freem(nd->nd_mrep); if (!error && nd->nd_repstat) error = nd->nd_repstat; free(ndp, M_NFSCLDELEG); return (error); } /* * Do a readlink rpc. */ int nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsnode *np = VTONFS(vp); nfsattrbit_t attrbits; int error, len, cangetattr = 1; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_READLINK, vp, cred); if (nd->nd_flag & ND_NFSV4) { /* * And do a Getattr op. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); (void) nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (nd->nd_flag & ND_NFSV3) error = nfscl_postop_attr(nd, nap, attrflagp); if (!nd->nd_repstat && !error) { NFSM_STRSIZ(len, NFS_MAXPATHLEN); /* * This seems weird to me, but must have been added to * FreeBSD for some reason. The only thing I can think of * is that there was/is some server that replies with * more link data than it should? */ if (len == NFS_MAXPATHLEN) { NFSLOCKNODE(np); if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) { len = np->n_size; cangetattr = 0; } NFSUNLOCKNODE(np); } error = nfsm_mbufuio(nd, uiop, len); if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr) error = nfscl_postop_attr(nd, nap, attrflagp); } if (nd->nd_repstat && !error) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * Read operation. */ int nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) { int error, expireret = 0, retrycnt; u_int32_t clidrev = 0; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *np = VTONFS(vp); struct ucred *newcred; struct nfsfh *nfhp = NULL; nfsv4stateid_t stateid; void *lckp; if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; newcred = cred; if (NFSHASNFSV4(nmp)) { nfhp = np->n_fhp; newcred = NFSNEWCRED(cred); } retrycnt = 0; do { lckp = NULL; if (NFSHASNFSV4(nmp)) (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid, &lckp); error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap, attrflagp); if (error == NFSERR_OPENMODE) { NFSLOCKMNT(nmp); nmp->nm_state |= NFSSTA_OPENMODE; NFSUNLOCKMNT(nmp); } if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) nfscl_lockderef(lckp); 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_read"); } else if ((error == NFSERR_EXPIRED || ((!NFSHASINT(nmp) || !NFSHASNFSV4N(nmp)) && error == NFSERR_BADSTATEID)) && clidrev != 0) { expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp) && NFSHASNFSV4N(nmp)) { error = EIO; } retrycnt++; } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || error == NFSERR_BADSESSION || (error == NFSERR_OLDSTATEID && retrycnt < 20) || ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && expireret == 0 && clidrev != 0 && retrycnt < 4) || (error == NFSERR_OPENMODE && retrycnt < 4)); if (error && retrycnt >= 4) error = EIO; if (NFSHASNFSV4(nmp)) NFSFREECRED(newcred); return (error); } /* * The actual read RPC. */ static int nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) { u_int32_t *tl; int error = 0, len, retlen, tsiz, eof = 0; struct nfsrv_descript nfsd; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsrv_descript *nd = &nfsd; int rsize; off_t tmp_off; *attrflagp = 0; tsiz = uiop->uio_resid; tmp_off = uiop->uio_offset + tsiz; NFSLOCKMNT(nmp); if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { NFSUNLOCKMNT(nmp); return (EFBIG); } rsize = nmp->nm_rsize; NFSUNLOCKMNT(nmp); nd->nd_mrep = NULL; while (tsiz > 0) { *attrflagp = 0; len = (tsiz > rsize) ? rsize : tsiz; NFSCL_REQSTART(nd, NFSPROC_READ, vp, cred); if (nd->nd_flag & ND_NFSV4) nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); if (nd->nd_flag & ND_NFSV2) { *tl++ = txdr_unsigned(uiop->uio_offset); *tl++ = txdr_unsigned(len); *tl = 0; } else { txdr_hyper(uiop->uio_offset, tl); *(tl + 2) = txdr_unsigned(len); } /* * Since I can't do a Getattr for NFSv4 for Write, there * doesn't seem any point in doing one here, either. * (See the comment in nfsrpc_writerpc() for more info.) */ error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (nd->nd_flag & ND_NFSV3) { error = nfscl_postop_attr(nd, nap, attrflagp); } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { error = nfsm_loadattr(nd, nap); if (!error) *attrflagp = 1; } if (nd->nd_repstat || error) { if (!error) error = nd->nd_repstat; goto nfsmout; } if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); eof = fxdr_unsigned(int, *(tl + 1)); } else if (nd->nd_flag & ND_NFSV4) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); eof = fxdr_unsigned(int, *tl); } NFSM_STRSIZ(retlen, len); error = nfsm_mbufuio(nd, uiop, retlen); if (error) goto nfsmout; m_freem(nd->nd_mrep); nd->nd_mrep = NULL; tsiz -= retlen; if (!(nd->nd_flag & ND_NFSV2)) { if (eof || retlen == 0) tsiz = 0; } else if (retlen < len) tsiz = 0; } return (0); nfsmout: if (nd->nd_mrep != NULL) m_freem(nd->nd_mrep); return (error); } /* * nfs write operation * When called_from_strategy != 0, it should return EIO for an error that * indicates recovery is in progress, so that the buffer will be left * dirty and be written back to the server later. If it loops around, * the recovery thread could get stuck waiting for the buffer and recovery * will then deadlock. */ int nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, int called_from_strategy, int ioflag) { int error, expireret = 0, retrycnt, nostateid; u_int32_t clidrev = 0; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *np = VTONFS(vp); struct ucred *newcred; struct nfsfh *nfhp = NULL; nfsv4stateid_t stateid; void *lckp; KASSERT(*must_commit >= 0 && *must_commit <= 2, ("nfsrpc_write: must_commit out of range=%d", *must_commit)); if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; newcred = cred; if (NFSHASNFSV4(nmp)) { newcred = NFSNEWCRED(cred); nfhp = np->n_fhp; } retrycnt = 0; do { lckp = NULL; nostateid = 0; if (NFSHASNFSV4(nmp)) { (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid, &lckp); if (stateid.other[0] == 0 && stateid.other[1] == 0 && stateid.other[2] == 0) { nostateid = 1; NFSCL_DEBUG(1, "stateid0 in write\n"); } } /* * If there is no stateid for NFSv4, it means this is an * extraneous write after close. Basically a poorly * implemented buffer cache. Just don't do the write. */ if (nostateid) error = 0; else error = nfsrpc_writerpc(vp, uiop, iomode, must_commit, newcred, &stateid, p, nap, attrflagp, ioflag); if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) nfscl_lockderef(lckp); 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_write"); } else if ((error == NFSERR_EXPIRED || ((!NFSHASINT(nmp) || !NFSHASNFSV4N(nmp)) && error == NFSERR_BADSTATEID)) && clidrev != 0) { expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp) && NFSHASNFSV4N(nmp)) { error = EIO; } retrycnt++; } while (error == NFSERR_GRACE || error == NFSERR_DELAY || ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) || (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) && called_from_strategy != 0))) error = EIO; if (NFSHASNFSV4(nmp)) NFSFREECRED(newcred); return (error); } /* * The actual write RPC. */ static int nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, int ioflag) { u_int32_t *tl; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *np = VTONFS(vp); int error = 0, len, rlen, commit, committed = NFSWRITE_FILESYNC; int wccflag = 0; int32_t backup; struct nfsrv_descript *nd; nfsattrbit_t attrbits; uint64_t tmp_off; ssize_t tsiz, wsize; bool do_append; KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); *attrflagp = 0; tsiz = uiop->uio_resid; tmp_off = uiop->uio_offset + tsiz; NFSLOCKMNT(nmp); if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { NFSUNLOCKMNT(nmp); return (EFBIG); } wsize = nmp->nm_wsize; do_append = false; if ((ioflag & IO_APPEND) != 0 && NFSHASNFSV4(nmp) && !NFSHASPNFS(nmp)) do_append = true; NFSUNLOCKMNT(nmp); nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK); nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ while (tsiz > 0) { *attrflagp = 0; len = (tsiz > wsize) ? wsize : tsiz; if (do_append) NFSCL_REQSTART(nd, NFSPROC_APPENDWRITE, vp, cred); else NFSCL_REQSTART(nd, NFSPROC_WRITE, vp, cred); if (nd->nd_flag & ND_NFSV4) { if (do_append) { NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_HYPER); *tl++ = txdr_unsigned(NFSX_HYPER); txdr_hyper(uiop->uio_offset, tl); tl += 2; *tl = txdr_unsigned(NFSV4OP_WRITE); } nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED); txdr_hyper(uiop->uio_offset, tl); tl += 2; *tl++ = txdr_unsigned(*iomode); *tl = txdr_unsigned(len); } else if (nd->nd_flag & ND_NFSV3) { NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED); txdr_hyper(uiop->uio_offset, tl); tl += 2; *tl++ = txdr_unsigned(len); *tl++ = txdr_unsigned(*iomode); *tl = txdr_unsigned(len); } else { u_int32_t x; NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); /* * Not sure why someone changed this, since the * RFC clearly states that "beginoffset" and * "totalcount" are ignored, but it wouldn't * surprise me if there's a busted server out there. */ /* Set both "begin" and "current" to non-garbage. */ x = txdr_unsigned((u_int32_t)uiop->uio_offset); *tl++ = x; /* "begin offset" */ *tl++ = x; /* "current offset" */ x = txdr_unsigned(len); *tl++ = x; /* total to this offset */ *tl = x; /* size of this write */ } error = nfsm_uiombuf(nd, uiop, len); if (error != 0) { m_freem(nd->nd_mreq); free(nd, M_TEMP); return (error); } /* * Although it is tempting to do a normal Getattr Op in the * NFSv4 compound, the result can be a nearly hung client * system if the Getattr asks for Owner and/or OwnerGroup. * It occurs when the client can't map either the Owner or * Owner_group name in the Getattr reply to a uid/gid. When * there is a cache miss, the kernel does an upcall to the * nfsuserd. Then, it can try and read the local /etc/passwd * or /etc/group file. It can then block in getnewbuf(), * waiting for dirty writes to be pushed to the NFS server. * The only reason this doesn't result in a complete * deadlock, is that the upcall times out and allows * the write to complete. However, progress is so slow * that it might just as well be deadlocked. * As such, we get the rest of the attributes, but not * Owner or Owner_group. * nb: nfscl_loadattrcache() needs to be told that these * partial attributes from a write rpc are being * passed in, via a argument flag. */ if (nd->nd_flag & ND_NFSV4) { NFSWRITEGETATTR_ATTRBIT(&attrbits); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, vp, p, cred); if (error) { free(nd, M_TEMP); return (error); } if (nd->nd_repstat) { /* * In case the rpc gets retried, roll * the uio fields changed by nfsm_uiombuf() * back. */ uiop->uio_offset -= len; uiop->uio_resid += len; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - len; uiop->uio_iov->iov_len += len; } if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { error = nfscl_wcc_data(nd, vp, nap, attrflagp, &wccflag, &tmp_off); if (error) goto nfsmout; } if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == (ND_NFSV4 | ND_NOMOREDATA) && nd->nd_repstat == NFSERR_NOTSAME && do_append) { /* * Verify of the file's size failed, so redo the * write using the file's size as returned in * the wcc attributes. */ if (tmp_off + tsiz <= nmp->nm_maxfilesize) { do_append = false; uiop->uio_offset = tmp_off; m_freem(nd->nd_mrep); nd->nd_mrep = NULL; continue; } else nd->nd_repstat = EFBIG; } if (!nd->nd_repstat) { if (do_append) { /* Strip off the Write reply status. */ do_append = false; NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); } if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); rlen = fxdr_unsigned(int, *tl++); if (rlen == 0) { error = NFSERR_IO; goto nfsmout; } else if (rlen < len) { backup = len - rlen; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - backup; uiop->uio_iov->iov_len += backup; uiop->uio_offset -= backup; uiop->uio_resid += backup; len = rlen; } commit = fxdr_unsigned(int, *tl++); /* * Return the lowest commitment level * obtained by any of the RPCs. */ if (committed == NFSWRITE_FILESYNC) committed = commit; else if (committed == NFSWRITE_DATASYNC && commit == NFSWRITE_UNSTABLE) committed = commit; NFSLOCKMNT(nmp); if (!NFSHASWRITEVERF(nmp)) { NFSBCOPY((caddr_t)tl, (caddr_t)&nmp->nm_verf[0], NFSX_VERF); NFSSETWRITEVERF(nmp); } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF) && *must_commit != 2) { *must_commit = 1; NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); } NFSUNLOCKMNT(nmp); } if (nd->nd_flag & ND_NFSV4) NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) { error = nfsm_loadattr(nd, nap); if (!error) *attrflagp = NFS_LATTR_NOSHRINK; } } else { error = nd->nd_repstat; } if (error) goto nfsmout; NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4)); m_freem(nd->nd_mrep); nd->nd_mrep = NULL; tsiz -= len; } nfsmout: if (nd->nd_mrep != NULL) m_freem(nd->nd_mrep); *iomode = committed; if (nd->nd_repstat && !error) error = nd->nd_repstat; free(nd, M_TEMP); return (error); } /* * Do an nfs deallocate operation. */ int nfsrpc_deallocate(vnode_t vp, off_t offs, off_t len, struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) { int error, expireret = 0, openerr, retrycnt; uint32_t clidrev = 0; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsfh *nfhp; nfsv4stateid_t stateid; void *lckp; if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; retrycnt = 0; do { lckp = NULL; openerr = 1; nfhp = VTONFS(vp)->n_fhp; error = nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp); if (error != 0) { /* * No Open stateid, so try and open the file * now. */ openerr = nfsrpc_open(vp, FWRITE, cred, p); if (openerr == 0) nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp); } error = nfsrpc_deallocaterpc(vp, offs, len, &stateid, nap, attrflagp, cred, p); if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) nfscl_lockderef(lckp); if (openerr == 0) nfsrpc_close(vp, 0, p); 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_deallocate"); } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && error == NFSERR_BADSTATEID)) && clidrev != 0) { expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) { error = EIO; } retrycnt++; } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || error == NFSERR_BADSESSION || (error == NFSERR_OLDSTATEID && retrycnt < 20) || ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && expireret == 0 && clidrev != 0 && retrycnt < 4)); if (error && retrycnt >= 4) error = EIO; return (error); } /* * The actual deallocate RPC. */ static int nfsrpc_deallocaterpc(vnode_t vp, off_t offs, off_t len, nfsv4stateid_t *stateidp, struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsnode *np = VTONFS(vp); int error, wccflag; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; nfsattrbit_t attrbits; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_DEALLOCATE, vp, cred); nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER); txdr_hyper(offs, tl); tl += 2; txdr_hyper(len, tl); NFSWRITEGETATTR_ATTRBIT(&attrbits); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, p, cred); if (error != 0) return (error); wccflag = 0; error = nfscl_wcc_data(nd, vp, nap, attrflagp, &wccflag, NULL); if (error != 0) goto nfsmout; if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); error = nfsm_loadattr(nd, nap); if (error != 0) goto nfsmout; *attrflagp = NFS_LATTR_NOSHRINK; } NFSWRITERPC_SETTIME(wccflag, np, nap, 1); nfsmout: m_freem(nd->nd_mrep); if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; return (error); } /* * nfs mknod rpc * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the * mode set to specify the file type and the size field for rdev. */ int nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, u_int32_t rdev, __enum_uint8(vtype) vtyp, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp) { u_int32_t *tl; int error = 0; struct nfsrv_descript nfsd, *nd = &nfsd; nfsattrbit_t attrbits; *nfhpp = NULL; *attrflagp = 0; *dattrflagp = 0; if (namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp, cred); if (nd->nd_flag & ND_NFSV4) { if (vtyp == VBLK || vtyp == VCHR) { NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); *tl++ = vtonfsv34_type(vtyp); *tl++ = txdr_unsigned(NFSMAJOR(rdev)); *tl = txdr_unsigned(NFSMINOR(rdev)); } else { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = vtonfsv34_type(vtyp); } } (void) nfsm_strtom(nd, name, namelen); if (nd->nd_flag & ND_NFSV3) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = vtonfsv34_type(vtyp); } if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); if ((nd->nd_flag & ND_NFSV3) && (vtyp == VCHR || vtyp == VBLK)) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSMAJOR(rdev)); *tl = txdr_unsigned(NFSMINOR(rdev)); } if (nd->nd_flag & ND_NFSV4) { NFSGETATTR_ATTRBIT(&attrbits); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_GETFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); } if (nd->nd_flag & ND_NFSV2) nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev); error = nfscl_request(nd, dvp, p, cred); if (error) return (error); if (nd->nd_flag & ND_NFSV4) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); if (!nd->nd_repstat) { if (nd->nd_flag & ND_NFSV4) { NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error) goto nfsmout; } error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); if (error) goto nfsmout; } if (nd->nd_flag & ND_NFSV3) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); if (!error && nd->nd_repstat) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * nfs file create call * Mostly just call the approriate routine. (I separated out v4, so that * error recovery wouldn't be as difficult.) */ int nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp) { int error = 0, newone, expireret = 0, retrycnt, unlocked; struct nfsclowner *owp; struct nfscldeleg *dp; struct nfsmount *nmp = VFSTONFS(dvp->v_mount); u_int32_t clidrev; if (NFSHASNFSV4(nmp)) { retrycnt = 0; do { dp = NULL; error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone, NULL, 1, true); if (error) return (error); if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; else clidrev = 0; if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || retrycnt > 0) error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, &unlocked); else error = nfsrpc_getcreatelayout(dvp, name, namelen, vap, cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, &unlocked); /* * There is no need to invalidate cached attributes here, * since new post-delegation issue attributes are always * returned by nfsrpc_createv4() and these will update the * attribute cache. */ if (dp != NULL) (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, dp); nfscl_ownerrelease(nmp, owp, error, newone, unlocked); if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || error == NFSERR_BADSESSION) { (void) nfs_catnap(PZERO, error, "nfs_open"); } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && clidrev != 0) { expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); retrycnt++; } } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || error == NFSERR_BADSESSION || ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && expireret == 0 && clidrev != 0 && retrycnt < 4)); if (error && retrycnt >= 4) error = EIO; } else { error = nfsrpc_createv23(dvp, name, namelen, vap, cverf, fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp); } return (error); } /* * The create rpc for v2 and 3. */ static int nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap, nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp) { u_int32_t *tl; int error = 0; struct nfsrv_descript nfsd, *nd = &nfsd; *nfhpp = NULL; *attrflagp = 0; *dattrflagp = 0; if (namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp, cred); (void) nfsm_strtom(nd, name, namelen); if (nd->nd_flag & ND_NFSV3) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); if (fmode & O_EXCL) { *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); *tl++ = cverf.lval[0]; *tl = cverf.lval[1]; } else { *tl = txdr_unsigned(NFSCREATE_UNCHECKED); nfscl_fillsattr(nd, vap, dvp, 0, 0); } } else { nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0); } error = nfscl_request(nd, dvp, p, cred); if (error) return (error); if (nd->nd_repstat == 0) { error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); if (error) goto nfsmout; } if (nd->nd_flag & ND_NFSV3) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } static int nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, int *unlockedp) { u_int32_t *tl; int error = 0, deleg, newone, ret, acesize, limitby; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsclopen *op; struct nfscldeleg *dp = NULL; struct nfsnode *np; struct nfsfh *nfhp; nfsattrbit_t attrbits; nfsv4stateid_t stateid; u_int32_t rflags; struct nfsmount *nmp; struct nfsclsession *tsep; nmp = VFSTONFS(dvp->v_mount); np = VTONFS(dvp); *unlockedp = 0; *nfhpp = NULL; *dpp = NULL; *attrflagp = 0; *dattrflagp = 0; if (namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp, cred); /* * For V4, this is actually an Open op. */ NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(owp->nfsow_seqid); if (NFSHASNFSV4N(nmp)) { if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 && nfs_numnfscbd > 0) *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTWRITEDELEG); else *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTNODELEG); } else *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD); *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; *tl = tsep->nfsess_clientid.lval[1]; (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); if (fmode & O_EXCL) { if (NFSHASNFSV4N(nmp)) { if (NFSHASSESSPERSIST(nmp)) { /* Use GUARDED for persistent sessions. */ *tl = txdr_unsigned(NFSCREATE_GUARDED); nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } else { /* Otherwise, use EXCLUSIVE4_1. */ *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); *tl++ = cverf.lval[0]; *tl = cverf.lval[1]; nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } } else { /* NFSv4.0 */ *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); *tl++ = cverf.lval[0]; *tl = cverf.lval[1]; } } else { *tl = txdr_unsigned(NFSCREATE_UNCHECKED); nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); (void) nfsm_strtom(nd, name, namelen); /* Get the new file's handle and attributes. */ NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_GETFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); (void) nfsrv_putattrbit(nd, &attrbits); /* Get the directory's post-op attributes. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, dvp, p, cred); if (error) return (error); NFSCL_INCRSEQID(owp->nfsow_seqid, nd); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); stateid.seqid = *tl++; stateid.other[0] = *tl++; stateid.other[1] = *tl++; stateid.other[2] = *tl; rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(int, *tl); if (deleg == NFSV4OPEN_DELEGATEREAD || deleg == NFSV4OPEN_DELEGATEWRITE) { if (!(owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_FIRSTDELEG)) owp->nfsow_clp->nfsc_flags |= (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); dp = malloc( sizeof (struct nfscldeleg) + NFSX_V4FHMAX, M_NFSCLDELEG, M_WAITOK); LIST_INIT(&dp->nfsdl_owner); LIST_INIT(&dp->nfsdl_lock); dp->nfsdl_clp = owp->nfsow_clp; newnfs_copyincred(cred, &dp->nfsdl_cred); nfscl_lockinit(&dp->nfsdl_rwlock); NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); dp->nfsdl_stateid.seqid = *tl++; dp->nfsdl_stateid.other[0] = *tl++; dp->nfsdl_stateid.other[1] = *tl++; dp->nfsdl_stateid.other[2] = *tl++; ret = fxdr_unsigned(int, *tl); if (deleg == NFSV4OPEN_DELEGATEWRITE) { dp->nfsdl_flags = NFSCLDL_WRITE; /* * Indicates how much the file can grow. */ NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); limitby = fxdr_unsigned(int, *tl++); switch (limitby) { case NFSV4OPEN_LIMITSIZE: dp->nfsdl_sizelimit = fxdr_hyper(tl); break; case NFSV4OPEN_LIMITBLOCKS: dp->nfsdl_sizelimit = fxdr_unsigned(u_int64_t, *tl++); dp->nfsdl_sizelimit *= fxdr_unsigned(u_int64_t, *tl); break; default: error = NFSERR_BADXDR; goto nfsmout; } } else { dp->nfsdl_flags = NFSCLDL_READ; } if (ret) dp->nfsdl_flags |= NFSCLDL_RECALL; error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false, &ret, &acesize, p); if (error) goto nfsmout; } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && NFSHASNFSV4N(nmp)) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(uint32_t, *tl); if (deleg == NFSV4OPEN_CONTENTION || deleg == NFSV4OPEN_RESOURCE) NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; } error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); if (error) goto nfsmout; /* Get rid of the PutFH and Getattr status values. */ NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); /* Load the directory attributes. */ error = nfsm_loadattr(nd, dnap); if (error) goto nfsmout; *dattrflagp = 1; if (dp != NULL && *attrflagp) { dp->nfsdl_change = nnap->na_filerev; dp->nfsdl_modtime = nnap->na_mtime; dp->nfsdl_flags |= NFSCLDL_MODTIMESET; } /* * We can now complete the Open state. */ nfhp = *nfhpp; if (dp != NULL) { dp->nfsdl_fhlen = nfhp->nfh_len; NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); } /* * Get an Open structure that will be * attached to the OpenOwner, acquired already. */ error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, cred, p, NULL, &op, &newone, NULL, 0, false); if (error) goto nfsmout; op->nfso_stateid = stateid; newnfs_copyincred(cred, &op->nfso_cred); if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { do { ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, nfhp->nfh_len, op, cred, p); if (ret == NFSERR_DELAY) (void) nfs_catnap(PZERO, ret, "nfs_create"); } while (ret == NFSERR_DELAY); error = ret; } /* * If the server is handing out delegations, but we didn't * get one because an OpenConfirm was required, try the * Open again, to get a delegation. This is a harmless no-op, * from a server's point of view. */ if ((rflags & NFSV4OPEN_RESULTCONFIRM) && (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && !error && dp == NULL) { KASSERT(!NFSHASNFSV4N(nmp), ("nfsrpc_createv4: result confirm")); do { ret = nfsrpc_openrpc(VFSTONFS(dvp->v_mount), dvp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, nfhp->nfh_fh, nfhp->nfh_len, (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, name, namelen, &dp, 0, 0x0, cred, p, 0, 1); if (ret == NFSERR_DELAY) (void) nfs_catnap(PZERO, ret, "nfs_crt2"); } while (ret == NFSERR_DELAY); if (ret) { if (dp != NULL) { free(dp, M_NFSCLDELEG); dp = NULL; } if (ret == NFSERR_STALECLIENTID || ret == NFSERR_STALEDONTRECOVER || ret == NFSERR_BADSESSION) error = ret; } } nfscl_openrelease(nmp, op, error, newone); *unlockedp = 1; } if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; if (error == NFSERR_STALECLIENTID) nfscl_initiate_recovery(owp->nfsow_clp); nfsmout: if (!error) *dpp = dp; else if (dp != NULL) free(dp, M_NFSCLDELEG); m_freem(nd->nd_mrep); return (error); } /* * Nfs remove rpc */ int nfsrpc_remove(struct vnode *dvp, char *name, int namelen, struct vnode *vp, struct nfsvattr *nap, int *attrflagp, nfsremove_status *file_status, struct nfsvattr *dnap, int *dattrflagp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsnode *np; struct nfsmount *nmp; nfsv4stateid_t dstateid; nfsattrbit_t attrbits; int error, i, ret; *dattrflagp = 0; *attrflagp = 0; *file_status = UNKNOWN; ret = 0; if (namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); nmp = VFSTONFS(dvp->v_mount); tryagain: if (NFSHASNFSV4(nmp) && ((nmp->nm_flag & NFSMNT_NOCTO) == 0 || !NFSHASNFSV4N(nmp)) && ret == 0) { ret = nfscl_removedeleg(vp, p, &dstateid); if (ret == 1) { NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp, cred); NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); if (NFSHASNFSV4N(nmp)) *tl++ = 0; else *tl++ = dstateid.seqid; *tl++ = dstateid.other[0]; *tl++ = dstateid.other[1]; *tl++ = dstateid.other[2]; *tl = txdr_unsigned(NFSV4OP_PUTFH); np = VTONFS(dvp); (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_REMOVE); } } else { ret = 0; } if (ret == 0) NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp, cred); (void)nfsm_strtom(nd, name, namelen); if (ret == 0 && (nd->nd_flag & ND_NFSV4) != 0) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); np = VTONFS(vp); (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); NFSGETATTR_ATTRBIT(&attrbits); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void)nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, dvp, p, cred); if (error != 0) return (error); if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { /* For NFSv4, parse out any Delereturn replies. */ if (ret > 0 && nd->nd_repstat != 0 && (nd->nd_flag & ND_NOMOREDATA)) { /* * If the Delegreturn failed, try again without * it. The server will Recall, as required. */ m_freem(nd->nd_mrep); goto tryagain; } for (i = 0; i < (ret * 2); i++) { if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1)) nd->nd_flag |= ND_NOMOREDATA; } } error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); } if (ret == 0 && (nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { /* Parse out the Remove reply for NFSPROC_REMOVE. */ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + 2 * NFSX_HYPER); /* No use for change info for now. */ /* The Remove succeeded. */ nd->nd_repstat = 0; } if (ret == 0 && (nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { /* Parse out the PutFH, Getattr for NFSPROC_REMOVE. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1) != 0) { i = fxdr_unsigned(int, *(tl + 1)); if (i == NFSERR_STALE) *file_status = DELETED; } else { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1) != 0) { i = fxdr_unsigned(int, *(tl + 1)); if (i == NFSERR_STALE) *file_status = DELETED; } else { error = nfsm_loadattr(nd, nap); if (error == 0) { *attrflagp = 1; if (nap->na_nlink == 0) *file_status = NLINK_ZERO; else *file_status = VALID; } } } } if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * Do an nfs rename rpc. */ int nfsrpc_rename(struct vnode *fdvp, struct vnode *fvp, char *fnameptr, int fnamelen, struct vnode *tdvp, struct vnode *tvp, char *tnameptr, int tnamelen, nfsremove_status *tvp_status, struct nfsvattr *fnap, struct nfsvattr *tnap, int *fattrflagp, int *tattrflagp, struct nfsvattr *tvpnap, int *tvpattrflagp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp; struct nfsnode *np; nfsattrbit_t attrbits; nfsv4stateid_t fdstateid, tdstateid; int error = 0, ret = 0, gottd = 0, gotfd = 0, i; *fattrflagp = 0; *tattrflagp = 0; *tvpattrflagp = 0; *tvp_status = UNKNOWN; nmp = VFSTONFS(fdvp->v_mount); if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); tryagain: if (NFSHASNFSV4(nmp) && ((nmp->nm_flag & NFSMNT_NOCTO) == 0 || !NFSHASNFSV4N(nmp)) && ret == 0) { ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, &tdstateid, &gottd, p); if (gotfd && gottd) { NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp, cred); } else if (gotfd) { NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp, cred); } else if (gottd) { NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp, cred); } if (gotfd) { NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); if (NFSHASNFSV4N(nmp)) *tl++ = 0; else *tl++ = fdstateid.seqid; *tl++ = fdstateid.other[0]; *tl++ = fdstateid.other[1]; *tl = fdstateid.other[2]; if (gottd) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); np = VTONFS(tvp); (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); } } if (gottd) { NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); if (NFSHASNFSV4N(nmp)) *tl++ = 0; else *tl++ = tdstateid.seqid; *tl++ = tdstateid.other[0]; *tl++ = tdstateid.other[1]; *tl = tdstateid.other[2]; } if (ret > 0) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); np = VTONFS(fdvp); (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_SAVEFH); } } else { ret = 0; } if (ret == 0) NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp, cred); if ((nd->nd_flag & ND_NFSV4) != 0) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSWCCATTR_ATTRBIT(&attrbits); (void)nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, VTONFS(tdvp)->n_fhp->nfh_len, 0); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void)nfsrv_putattrbit(nd, &attrbits); nd->nd_flag |= ND_V4WCCATTR; NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_RENAME); } (void)nfsm_strtom(nd, fnameptr, fnamelen); if ((nd->nd_flag & ND_NFSV4) == 0) (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, VTONFS(tdvp)->n_fhp->nfh_len, 0); (void)nfsm_strtom(nd, tnameptr, tnamelen); if (ret == 0 && (nd->nd_flag & ND_NFSV4) != 0) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); /* When tvp == NULL, it doesn't matter which dvp is used. */ *tl = txdr_unsigned(NFSV4OP_PUTFH); if (tvp != NULL) (void)nfsm_fhtom(nmp, nd, VTONFS(tvp)->n_fhp->nfh_fh, VTONFS(tvp)->n_fhp->nfh_len, 0); else (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, VTONFS(tdvp)->n_fhp->nfh_len, 0); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); (void)nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, fdvp, p, cred); if (error != 0) return (error); if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { /* For NFSv4, parse out any Delereturn replies. */ if (ret > 0 && nd->nd_repstat != 0 && (nd->nd_flag & ND_NOMOREDATA)) { /* * If the Delegreturn failed, try again without * it. The server will Recall, as required. */ m_freem(nd->nd_mrep); goto tryagain; } for (i = 0; i < (ret * 2); i++) { if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1)) { if (i == 1 && ret > 1) { /* * If the Delegreturn failed, try again * without it. The server will Recall, as * required. * If ret > 1, the second iteration of this * loop is the second DelegReturn result. */ m_freem(nd->nd_mrep); goto tryagain; } else { nd->nd_flag |= ND_NOMOREDATA; } } } } /* Now, the first wcc attribute reply. */ if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1)) nd->nd_flag |= ND_NOMOREDATA; } error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, NULL); /* and the second wcc attribute reply. */ if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && error == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1)) nd->nd_flag |= ND_NOMOREDATA; } if (error == 0) error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, NULL, NULL); } if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && ret == 0 && error == 0) { /* Parse out the rename successful reply. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 4 * NFSX_HYPER); nd->nd_repstat = 0; /* Rename succeeded. */ /* Parse PutFH reply for tvp. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1) != 0) { if (tvp != NULL) { i = fxdr_unsigned(int, *(tl + 1)); if (i == NFSERR_STALE) *tvp_status = DELETED; } } else { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1) != 0) { if (tvp != NULL) { i = fxdr_unsigned(int, *(tl + 1)); if (i == NFSERR_STALE) *tvp_status = DELETED; } } else { error = nfsm_loadattr(nd, tvpnap); if (error == 0 && tvp != NULL) { *tvpattrflagp = 1; if (tvpnap->na_nlink == 0) *tvp_status = NLINK_ZERO; else *tvp_status = VALID; } } } } if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * nfs hard link create rpc */ int nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap, int *attrflagp, int *dattrflagp) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; nfsattrbit_t attrbits; int error = 0; *attrflagp = 0; *dattrflagp = 0; if (namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); NFSCL_REQSTART(nd, NFSPROC_LINK, vp, cred); if (nd->nd_flag & ND_NFSV4) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); } (void)nfsm_fhtom(VFSTONFS(dvp->v_mount), nd, VTONFS(dvp)->n_fhp->nfh_fh, VTONFS(dvp)->n_fhp->nfh_len, 0); if (nd->nd_flag & ND_NFSV4) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_LINK); } (void) nfsm_strtom(nd, name, namelen); if (nd->nd_flag & ND_NFSV4) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); (void)nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void)nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (nd->nd_flag & ND_NFSV3) { error = nfscl_postop_attr(nd, nap, attrflagp); if (!error) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); } else if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0) { /* * First and parse out the PutFH and Link results. */ NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED + 2 * NFSX_HYPER); if (*(tl + 3)) nd->nd_flag |= ND_NOMOREDATA; /* * Get the directory post-op attributes. */ if ((nd->nd_flag & ND_NOMOREDATA) == 0) error = nfscl_postop_attr(nd, dnap, dattrflagp); if (error == 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) { /* Get rid of the RestoreFH reply. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1)) nd->nd_flag |= ND_NOMOREDATA; } /* Get the file's post-op attributes. */ if (error == 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) error = nfscl_postop_attr(nd, nap, attrflagp); } if (nd->nd_repstat && !error) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * nfs symbolic link create rpc */ int nfsrpc_symlink(vnode_t dvp, char *name, int namelen, const char *target, struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp; int slen, error = 0; *nfhpp = NULL; *attrflagp = 0; *dattrflagp = 0; nmp = VFSTONFS(dvp->v_mount); slen = strlen(target); if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp, cred); if (nd->nd_flag & ND_NFSV4) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFLNK); (void) nfsm_strtom(nd, target, slen); } (void) nfsm_strtom(nd, name, namelen); if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) nfscl_fillsattr(nd, vap, dvp, 0, 0); if (!(nd->nd_flag & ND_NFSV4)) (void) nfsm_strtom(nd, target, slen); if (nd->nd_flag & ND_NFSV2) nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); error = nfscl_request(nd, dvp, p, cred); if (error) return (error); if (nd->nd_flag & ND_NFSV4) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); if ((nd->nd_flag & ND_NFSV3) && !error) { if (!nd->nd_repstat) error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); if (!error) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); } if (nd->nd_repstat && !error) error = nd->nd_repstat; m_freem(nd->nd_mrep); /* * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. * Only do this if vfs.nfs.ignore_eexist is set. * Never do this for NFSv4.1 or later minor versions, since sessions * should guarantee "exactly once" RPC semantics. */ if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || nmp->nm_minorvers == 0)) error = 0; return (error); } /* * nfs make dir rpc */ int nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; nfsattrbit_t attrbits; int error = 0; struct nfsfh *fhp; struct nfsmount *nmp; *nfhpp = NULL; *attrflagp = 0; *dattrflagp = 0; nmp = VFSTONFS(dvp->v_mount); fhp = VTONFS(dvp)->n_fhp; if (namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp, cred); if (nd->nd_flag & ND_NFSV4) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFDIR); } (void) nfsm_strtom(nd, name, namelen); nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1 | NFSSATTR_NEWFILE, 0); if (nd->nd_flag & ND_NFSV4) { NFSGETATTR_ATTRBIT(&attrbits); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_GETFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); (void)nfsm_fhtom(nmp, nd, fhp->nfh_fh, fhp->nfh_len, 0); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, dvp, p, cred); if (error) return (error); if (nd->nd_flag & ND_NFSV4) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); if (!nd->nd_repstat && !error) { if (nd->nd_flag & ND_NFSV4) { NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); } if (!error) error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) { /* Get rid of the PutFH and Getattr status values. */ NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); /* Load the directory attributes. */ error = nfsm_loadattr(nd, dnap); if (error == 0) *dattrflagp = 1; } } if ((nd->nd_flag & ND_NFSV3) && !error) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); if (nd->nd_repstat && !error) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); /* * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. * Only do this if vfs.nfs.ignore_eexist is set. * Never do this for NFSv4.1 or later minor versions, since sessions * should guarantee "exactly once" RPC semantics. */ if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || nmp->nm_minorvers == 0)) error = 0; return (error); } /* * nfs remove directory call */ int nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp) { struct nfsrv_descript nfsd, *nd = &nfsd; int error = 0; *dattrflagp = 0; if (namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp, cred); (void) nfsm_strtom(nd, name, namelen); error = nfscl_request(nd, dvp, p, cred); if (error) return (error); if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); if (nd->nd_repstat && !error) error = nd->nd_repstat; m_freem(nd->nd_mrep); /* * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. */ if (error == ENOENT) error = 0; return (error); } /* * Check to make sure the file name in a Readdir reply is valid. */ static bool nfscl_invalidfname(bool is_v4, char *name, int len) { int i; char *cp; if (is_v4 && ((len == 1 && name[0] == '.') || (len == 2 && name[0] == '.' && name[1] == '.'))) { printf("Readdir NFSv4 reply has dot or dotdot in it\n"); return (true); } cp = name; for (i = 0; i < len; i++, cp++) { if (*cp == '/' || *cp == '\0') { printf("Readdir reply file name had imbedded / or nul" " byte\n"); return (true); } } return (false); } /* * Readdir rpc. * Always returns with either uio_resid unchanged, if you are at the * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks * filled in. * I felt this would allow caching of directory blocks more easily * than returning a pertially filled block. * Directory offset cookies: * Oh my, what to do with them... * I can think of three ways to deal with them: * 1 - have the layer above these RPCs maintain a map between logical * directory byte offsets and the NFS directory offset cookies * 2 - pass the opaque directory offset cookies up into userland * and let the libc functions deal with them, via the system call * 3 - return them to userland in the "struct dirent", so future versions * of libc can use them and do whatever is necessary to make things work * above these rpc calls, in the meantime * For now, I do #3 by "hiding" the directory offset cookies after the * d_name field in struct dirent. This is space inside d_reclen that * will be ignored by anything that doesn't know about them. * The directory offset cookies are filled in as the last 8 bytes of * each directory entry, after d_name. Someday, the userland libc * functions may be able to use these. In the meantime, it satisfies * OpenBSD's requirements for cookies being returned. * If expects the directory offset cookie for the read to be in uio_offset * and returns the one for the next entry after this directory block in * there, as well. */ int nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, int *eofp) { int len, left; struct dirent *dp = NULL; u_int32_t *tl; nfsquad_t cookie, ncookie; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *dnp = VTONFS(vp); struct nfsvattr nfsva; struct nfsrv_descript nfsd, *nd = &nfsd; int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; char *cp; nfsattrbit_t attrbits, dattrbits; u_int32_t rderr, *tl2 = NULL; size_t tresid; bool validentry; KASSERT(uiop->uio_iovcnt == 1 && (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, ("nfs readdirrpc bad uio")); KASSERT(uiop->uio_segflg == UIO_SYSSPACE, ("nfsrpc_readdir: uio userspace")); ncookie.lval[0] = ncookie.lval[1] = 0; /* * There is no point in reading a lot more than uio_resid, however * adding one additional DIRBLKSIZ makes sense. Since uio_resid * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this * will never make readsize > nm_readdirsize. */ readsize = nmp->nm_readdirsize; if (readsize > uiop->uio_resid) readsize = uiop->uio_resid + DIRBLKSIZ; *attrflagp = 0; if (eofp) *eofp = 0; tresid = uiop->uio_resid; cookie.lval[0] = cookiep->nfsuquad[0]; cookie.lval[1] = cookiep->nfsuquad[1]; nd->nd_mrep = NULL; /* * For NFSv4, first create the "." and ".." entries. */ if (NFSHASNFSV4(nmp)) { reqsize = 6 * NFSX_UNSIGNED; NFSGETATTR_ATTRBIT(&dattrbits); NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, NFSATTRBIT_MOUNTEDONFILEID)) { NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MOUNTEDONFILEID); gotmnton = 1; } else { /* * Must fake it. Use the fileno, except when the * fsid is != to that of the directory. For that * case, generate a fake fileno that is not the same. */ NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); gotmnton = 0; } /* * Joy, oh joy. For V4 we get to hand craft '.' and '..'. */ if (uiop->uio_offset == 0) { NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_GETFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, p, cred); if (error) return (error); dotfileid = 0; /* Fake out the compiler. */ if ((nd->nd_flag & ND_NOMOREDATA) == 0) { error = nfsm_loadattr(nd, &nfsva); if (error != 0) goto nfsmout; dotfileid = nfsva.na_fileid; } if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); len = fxdr_unsigned(int, *(tl + 4)); if (len > 0 && len <= NFSX_V4FHMAX) error = nfsm_advance(nd, NFSM_RNDUP(len), -1); else error = EPERM; if (!error) { NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); nfsva.na_mntonfileno = UINT64_MAX; error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, p, cred); if (error) { dotdotfileid = dotfileid; } else if (gotmnton) { if (nfsva.na_mntonfileno != UINT64_MAX) dotdotfileid = nfsva.na_mntonfileno; else dotdotfileid = nfsva.na_fileid; } else if (nfsva.na_filesid[0] == dnp->n_vattr.na_filesid[0] && nfsva.na_filesid[1] == dnp->n_vattr.na_filesid[1]) { dotdotfileid = nfsva.na_fileid; } else { do { fakefileno--; } while (fakefileno == nfsva.na_fileid); dotdotfileid = fakefileno; } } } else if (nd->nd_repstat == NFSERR_NOENT) { /* * Lookupp returns NFSERR_NOENT when we are * at the root, so just use the current dir. */ nd->nd_repstat = 0; dotdotfileid = dotfileid; } else { error = nd->nd_repstat; } m_freem(nd->nd_mrep); if (error) return (error); nd->nd_mrep = NULL; dp = (struct dirent *)uiop->uio_iov->iov_base; dp->d_pad0 = dp->d_pad1 = 0; dp->d_off = 0; dp->d_type = DT_DIR; dp->d_fileno = dotfileid; dp->d_namlen = 1; *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ dp->d_name[0] = '.'; dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; /* * Just make these offset cookie 0. */ tl = (u_int32_t *)&dp->d_name[8]; *tl++ = 0; *tl = 0; blksiz += dp->d_reclen; uiop->uio_resid -= dp->d_reclen; uiop->uio_offset += dp->d_reclen; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + dp->d_reclen; uiop->uio_iov->iov_len -= dp->d_reclen; dp = (struct dirent *)uiop->uio_iov->iov_base; dp->d_pad0 = dp->d_pad1 = 0; dp->d_off = 0; dp->d_type = DT_DIR; dp->d_fileno = dotdotfileid; dp->d_namlen = 2; *((uint64_t *)dp->d_name) = 0; dp->d_name[0] = '.'; dp->d_name[1] = '.'; dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; /* * Just make these offset cookie 0. */ tl = (u_int32_t *)&dp->d_name[8]; *tl++ = 0; *tl = 0; blksiz += dp->d_reclen; uiop->uio_resid -= dp->d_reclen; uiop->uio_offset += dp->d_reclen; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + dp->d_reclen; uiop->uio_iov->iov_len -= dp->d_reclen; } NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); } else { reqsize = 5 * NFSX_UNSIGNED; } /* * Loop around doing readdir rpc's of size readsize. * The stopping criteria is EOF or buffer full. */ while (more_dirs && bigenough) { *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_READDIR, vp, cred); if (nd->nd_flag & ND_NFSV2) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = cookie.lval[1]; *tl = txdr_unsigned(readsize); } else { NFSM_BUILD(tl, u_int32_t *, reqsize); *tl++ = cookie.lval[0]; *tl++ = cookie.lval[1]; if (cookie.qval == 0) { *tl++ = 0; *tl++ = 0; } else { NFSLOCKNODE(dnp); *tl++ = dnp->n_cookieverf.nfsuquad[0]; *tl++ = dnp->n_cookieverf.nfsuquad[1]; NFSUNLOCKNODE(dnp); } if (nd->nd_flag & ND_NFSV4) { *tl++ = txdr_unsigned(readsize); *tl = txdr_unsigned(readsize); (void) nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &dattrbits); } else { *tl = txdr_unsigned(readsize); } } error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (!(nd->nd_flag & ND_NFSV2)) { if (nd->nd_flag & ND_NFSV3) error = nfscl_postop_attr(nd, nap, attrflagp); if (!nd->nd_repstat && !error) { NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); NFSLOCKNODE(dnp); dnp->n_cookieverf.nfsuquad[0] = *tl++; dnp->n_cookieverf.nfsuquad[1] = *tl; NFSUNLOCKNODE(dnp); } } if (nd->nd_repstat || error) { if (!error) error = nd->nd_repstat; goto nfsmout; } NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); more_dirs = fxdr_unsigned(int, *tl); if (!more_dirs) tryformoredirs = 0; /* loop through the dir entries, doctoring them to 4bsd form */ while (more_dirs && bigenough) { validentry = true; if (nd->nd_flag & ND_NFSV4) { NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); ncookie.lval[0] = *tl++; ncookie.lval[1] = *tl++; len = fxdr_unsigned(int, *tl); } else if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); nfsva.na_fileid = fxdr_hyper(tl); tl += 2; len = fxdr_unsigned(int, *tl); } else { NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); nfsva.na_fileid = fxdr_unsigned(uint64_t, *tl++); len = fxdr_unsigned(int, *tl); } if (len <= 0 || len > NFS_MAXNAMLEN) { error = EBADRPC; goto nfsmout; } tlen = roundup2(len, 8); if (tlen == len) tlen += 8; /* To ensure null termination. */ left = DIRBLKSIZ - blksiz; if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { NFSBZERO(uiop->uio_iov->iov_base, left); dp->d_reclen += left; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + left; uiop->uio_iov->iov_len -= left; uiop->uio_resid -= left; uiop->uio_offset += left; blksiz = 0; } if (_GENERIC_DIRLEN(len) + NFSX_HYPER > uiop->uio_resid) bigenough = 0; if (bigenough) { struct iovec saviov; off_t savoff; ssize_t savresid; int savblksiz; saviov.iov_base = uiop->uio_iov->iov_base; saviov.iov_len = uiop->uio_iov->iov_len; savoff = uiop->uio_offset; savresid = uiop->uio_resid; savblksiz = blksiz; dp = (struct dirent *)uiop->uio_iov->iov_base; dp->d_pad0 = dp->d_pad1 = 0; dp->d_off = 0; dp->d_namlen = len; dp->d_reclen = _GENERIC_DIRLEN(len) + NFSX_HYPER; dp->d_type = DT_UNKNOWN; blksiz += dp->d_reclen; if (blksiz == DIRBLKSIZ) blksiz = 0; uiop->uio_resid -= DIRHDSIZ; uiop->uio_offset += DIRHDSIZ; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + DIRHDSIZ; uiop->uio_iov->iov_len -= DIRHDSIZ; cp = uiop->uio_iov->iov_base; error = nfsm_mbufuio(nd, uiop, len); if (error) goto nfsmout; /* Check for an invalid file name. */ if (nfscl_invalidfname( (nd->nd_flag & ND_NFSV4) != 0, cp, len)) { /* Skip over this entry. */ uiop->uio_iov->iov_base = saviov.iov_base; uiop->uio_iov->iov_len = saviov.iov_len; uiop->uio_offset = savoff; uiop->uio_resid = savresid; blksiz = savblksiz; validentry = false; } else { cp = uiop->uio_iov->iov_base; tlen -= len; NFSBZERO(cp, tlen); cp += tlen; /* points to cookie store */ tl2 = (u_int32_t *)cp; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + tlen + NFSX_HYPER; uiop->uio_iov->iov_len -= tlen + NFSX_HYPER; uiop->uio_resid -= tlen + NFSX_HYPER; uiop->uio_offset += (tlen + NFSX_HYPER); } } else { error = nfsm_advance(nd, NFSM_RNDUP(len), -1); if (error) goto nfsmout; } if (nd->nd_flag & ND_NFSV4) { rderr = 0; nfsva.na_mntonfileno = UINT64_MAX; error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, &rderr, NULL, NULL, p, cred); if (error) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); } else if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); ncookie.lval[0] = *tl++; ncookie.lval[1] = *tl++; } else { NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); ncookie.lval[0] = 0; ncookie.lval[1] = *tl++; } if (bigenough && validentry) { if (nd->nd_flag & ND_NFSV4) { if (rderr) { dp->d_fileno = 0; } else { if (gotmnton) { if (nfsva.na_mntonfileno != UINT64_MAX) dp->d_fileno = nfsva.na_mntonfileno; else dp->d_fileno = nfsva.na_fileid; } else if (nfsva.na_filesid[0] == dnp->n_vattr.na_filesid[0] && nfsva.na_filesid[1] == dnp->n_vattr.na_filesid[1]) { dp->d_fileno = nfsva.na_fileid; } else { do { fakefileno--; } while (fakefileno == nfsva.na_fileid); dp->d_fileno = fakefileno; } dp->d_type = vtonfs_dtype(nfsva.na_type); } } else { dp->d_fileno = nfsva.na_fileid; } *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = ncookie.lval[0]; *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = ncookie.lval[1]; } more_dirs = fxdr_unsigned(int, *tl); } /* * If at end of rpc data, get the eof boolean */ if (!more_dirs) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); eof = fxdr_unsigned(int, *tl); if (tryformoredirs) more_dirs = !eof; if (nd->nd_flag & ND_NFSV4) { error = nfscl_postop_attr(nd, nap, attrflagp); if (error) goto nfsmout; } } m_freem(nd->nd_mrep); nd->nd_mrep = NULL; } /* * Fill last record, iff any, out to a multiple of DIRBLKSIZ * by increasing d_reclen for the last record. */ if (blksiz > 0) { left = DIRBLKSIZ - blksiz; NFSBZERO(uiop->uio_iov->iov_base, left); dp->d_reclen += left; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + left; uiop->uio_iov->iov_len -= left; uiop->uio_resid -= left; uiop->uio_offset += left; } /* * If returning no data, assume end of file. * If not bigenough, return not end of file, since you aren't * returning all the data * Otherwise, return the eof flag from the server. */ if (eofp) { if (tresid == ((size_t)(uiop->uio_resid))) *eofp = 1; else if (!bigenough) *eofp = 0; else *eofp = eof; } /* * Add extra empty records to any remaining DIRBLKSIZ chunks. */ while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) { dp = (struct dirent *)uiop->uio_iov->iov_base; NFSBZERO(dp, DIRBLKSIZ); dp->d_type = DT_UNKNOWN; tl = (u_int32_t *)&dp->d_name[4]; *tl++ = cookie.lval[0]; *tl = cookie.lval[1]; dp->d_reclen = DIRBLKSIZ; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + DIRBLKSIZ; uiop->uio_iov->iov_len -= DIRBLKSIZ; uiop->uio_resid -= DIRBLKSIZ; uiop->uio_offset += DIRBLKSIZ; } nfsmout: if (nd->nd_mrep != NULL) m_freem(nd->nd_mrep); return (error); } /* * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). * (Also used for NFS V4 when mount flag set.) * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) */ int nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, int *eofp) { int len, left; struct dirent *dp = NULL; u_int32_t *tl; vnode_t newvp = NULL; struct nfsrv_descript nfsd, *nd = &nfsd; struct nameidata nami, *ndp = &nami; struct componentname *cnp = &ndp->ni_cnd; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *dnp = VTONFS(vp), *np; struct nfsvattr nfsva; struct nfsfh *nfhp; nfsquad_t cookie, ncookie; int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; int isdotdot = 0, unlocknewvp = 0; u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; u_int64_t fileno = 0; char *cp; nfsattrbit_t attrbits, dattrbits; size_t tresid; u_int32_t *tl2 = NULL, rderr; struct timespec dctime, ts; bool attr_ok, named_dir, validentry; KASSERT(uiop->uio_iovcnt == 1 && (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, ("nfs readdirplusrpc bad uio")); KASSERT(uiop->uio_segflg == UIO_SYSSPACE, ("nfsrpc_readdirplus: uio userspace")); named_dir = false; if ((vp->v_irflag & VIRF_NAMEDDIR) != 0) named_dir = true; ncookie.lval[0] = ncookie.lval[1] = 0; timespecclear(&dctime); *attrflagp = 0; if (eofp != NULL) *eofp = 0; ndp->ni_dvp = vp; nd->nd_mrep = NULL; cookie.lval[0] = cookiep->nfsuquad[0]; cookie.lval[1] = cookiep->nfsuquad[1]; tresid = uiop->uio_resid; /* * For NFSv4, first create the "." and ".." entries. */ if (NFSHASNFSV4(nmp)) { NFSGETATTR_ATTRBIT(&dattrbits); NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, NFSATTRBIT_MOUNTEDONFILEID)) { NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MOUNTEDONFILEID); gotmnton = 1; } else { /* * Must fake it. Use the fileno, except when the * fsid is != to that of the directory. For that * case, generate a fake fileno that is not the same. */ NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); gotmnton = 0; } /* * Joy, oh joy. For V4 we get to hand craft '.' and '..'. */ if (uiop->uio_offset == 0) { NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_GETFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, p, cred); if (error) return (error); dotfileid = 0; /* Fake out the compiler. */ if ((nd->nd_flag & ND_NOMOREDATA) == 0) { error = nfsm_loadattr(nd, &nfsva); if (error != 0) goto nfsmout; dctime = nfsva.na_ctime; dotfileid = nfsva.na_fileid; } if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); len = fxdr_unsigned(int, *(tl + 4)); if (len > 0 && len <= NFSX_V4FHMAX) error = nfsm_advance(nd, NFSM_RNDUP(len), -1); else error = EPERM; if (!error) { NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); nfsva.na_mntonfileno = UINT64_MAX; error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, p, cred); if (error) { dotdotfileid = dotfileid; } else if (gotmnton) { if (nfsva.na_mntonfileno != UINT64_MAX) dotdotfileid = nfsva.na_mntonfileno; else dotdotfileid = nfsva.na_fileid; } else if (nfsva.na_filesid[0] == dnp->n_vattr.na_filesid[0] && nfsva.na_filesid[1] == dnp->n_vattr.na_filesid[1]) { dotdotfileid = nfsva.na_fileid; } else { do { fakefileno--; } while (fakefileno == nfsva.na_fileid); dotdotfileid = fakefileno; } } } else if (nd->nd_repstat == NFSERR_NOENT) { /* * Lookupp returns NFSERR_NOENT when we are * at the root, so just use the current dir. */ nd->nd_repstat = 0; dotdotfileid = dotfileid; } else { error = nd->nd_repstat; } m_freem(nd->nd_mrep); if (error) return (error); nd->nd_mrep = NULL; dp = (struct dirent *)uiop->uio_iov->iov_base; dp->d_pad0 = dp->d_pad1 = 0; dp->d_off = 0; dp->d_type = DT_DIR; dp->d_fileno = dotfileid; dp->d_namlen = 1; *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ dp->d_name[0] = '.'; dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; /* * Just make these offset cookie 0. */ tl = (u_int32_t *)&dp->d_name[8]; *tl++ = 0; *tl = 0; blksiz += dp->d_reclen; uiop->uio_resid -= dp->d_reclen; uiop->uio_offset += dp->d_reclen; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + dp->d_reclen; uiop->uio_iov->iov_len -= dp->d_reclen; dp = (struct dirent *)uiop->uio_iov->iov_base; dp->d_pad0 = dp->d_pad1 = 0; dp->d_off = 0; dp->d_type = DT_DIR; dp->d_fileno = dotdotfileid; dp->d_namlen = 2; *((uint64_t *)dp->d_name) = 0; dp->d_name[0] = '.'; dp->d_name[1] = '.'; dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; /* * Just make these offset cookie 0. */ tl = (u_int32_t *)&dp->d_name[8]; *tl++ = 0; *tl = 0; blksiz += dp->d_reclen; uiop->uio_resid -= dp->d_reclen; uiop->uio_offset += dp->d_reclen; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + dp->d_reclen; uiop->uio_iov->iov_len -= dp->d_reclen; } NFSREADDIRPLUS_ATTRBIT(&attrbits); if (gotmnton) NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MOUNTEDONFILEID); if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, NFSATTRBIT_TIMECREATE)) NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE); if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, NFSATTRBIT_HIDDEN) || !NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, NFSATTRBIT_SYSTEM)) { NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN); NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM); } } /* * Loop around doing readdir rpc's of size nm_readdirsize. * The stopping criteria is EOF or buffer full. */ while (more_dirs && bigenough) { *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp, cred); NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); *tl++ = cookie.lval[0]; *tl++ = cookie.lval[1]; if (cookie.qval == 0) { *tl++ = 0; *tl++ = 0; } else { NFSLOCKNODE(dnp); *tl++ = dnp->n_cookieverf.nfsuquad[0]; *tl++ = dnp->n_cookieverf.nfsuquad[1]; NFSUNLOCKNODE(dnp); } *tl++ = txdr_unsigned(nmp->nm_readdirsize); *tl = txdr_unsigned(nmp->nm_readdirsize); if (nd->nd_flag & ND_NFSV4) { (void) nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &dattrbits); } nanouptime(&ts); error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (nd->nd_flag & ND_NFSV3) error = nfscl_postop_attr(nd, nap, attrflagp); if (nd->nd_repstat || error) { if (!error) error = nd->nd_repstat; goto nfsmout; } if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0) dctime = nap->na_ctime; NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); NFSLOCKNODE(dnp); dnp->n_cookieverf.nfsuquad[0] = *tl++; dnp->n_cookieverf.nfsuquad[1] = *tl++; NFSUNLOCKNODE(dnp); more_dirs = fxdr_unsigned(int, *tl); if (!more_dirs) tryformoredirs = 0; /* loop through the dir entries, doctoring them to 4bsd form */ while (more_dirs && bigenough) { validentry = true; NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); if (nd->nd_flag & ND_NFSV4) { ncookie.lval[0] = *tl++; ncookie.lval[1] = *tl++; } else { fileno = fxdr_hyper(tl); tl += 2; } len = fxdr_unsigned(int, *tl); if (len <= 0 || len > NFS_MAXNAMLEN) { error = EBADRPC; goto nfsmout; } tlen = roundup2(len, 8); if (tlen == len) tlen += 8; /* To ensure null termination. */ left = DIRBLKSIZ - blksiz; if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { NFSBZERO(uiop->uio_iov->iov_base, left); dp->d_reclen += left; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + left; uiop->uio_iov->iov_len -= left; uiop->uio_resid -= left; uiop->uio_offset += left; blksiz = 0; } if (_GENERIC_DIRLEN(len) + NFSX_HYPER > uiop->uio_resid) bigenough = 0; if (bigenough) { struct iovec saviov; off_t savoff; ssize_t savresid; int savblksiz; saviov.iov_base = uiop->uio_iov->iov_base; saviov.iov_len = uiop->uio_iov->iov_len; savoff = uiop->uio_offset; savresid = uiop->uio_resid; savblksiz = blksiz; dp = (struct dirent *)uiop->uio_iov->iov_base; dp->d_pad0 = dp->d_pad1 = 0; dp->d_off = 0; dp->d_namlen = len; dp->d_reclen = _GENERIC_DIRLEN(len) + NFSX_HYPER; dp->d_type = DT_UNKNOWN; blksiz += dp->d_reclen; if (blksiz == DIRBLKSIZ) blksiz = 0; uiop->uio_resid -= DIRHDSIZ; uiop->uio_offset += DIRHDSIZ; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + DIRHDSIZ; uiop->uio_iov->iov_len -= DIRHDSIZ; cnp->cn_nameptr = uiop->uio_iov->iov_base; cnp->cn_namelen = len; NFSCNHASHZERO(cnp); cp = uiop->uio_iov->iov_base; error = nfsm_mbufuio(nd, uiop, len); if (error) goto nfsmout; /* Check for an invalid file name. */ if (nfscl_invalidfname( (nd->nd_flag & ND_NFSV4) != 0, cp, len)) { /* Skip over this entry. */ uiop->uio_iov->iov_base = saviov.iov_base; uiop->uio_iov->iov_len = saviov.iov_len; uiop->uio_offset = savoff; uiop->uio_resid = savresid; blksiz = savblksiz; validentry = false; } else { cp = uiop->uio_iov->iov_base; tlen -= len; NFSBZERO(cp, tlen); cp += tlen; /* points to cookie store */ tl2 = (u_int32_t *)cp; if (len == 2 && cnp->cn_nameptr[0] == '.' && cnp->cn_nameptr[1] == '.') isdotdot = 1; else isdotdot = 0; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + tlen + NFSX_HYPER; uiop->uio_iov->iov_len -= tlen + NFSX_HYPER; uiop->uio_resid -= tlen + NFSX_HYPER; uiop->uio_offset += (tlen + NFSX_HYPER); } } else { error = nfsm_advance(nd, NFSM_RNDUP(len), -1); if (error) goto nfsmout; } nfhp = NULL; if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); ncookie.lval[0] = *tl++; ncookie.lval[1] = *tl++; attrflag = fxdr_unsigned(int, *tl); if (attrflag) { error = nfsm_loadattr(nd, &nfsva); if (error) goto nfsmout; } NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); if (*tl) { error = nfsm_getfh(nd, &nfhp); if (error) goto nfsmout; } if (!attrflag && nfhp != NULL) { free(nfhp, M_NFSFH); nfhp = NULL; } } else { rderr = 0; nfsva.na_mntonfileno = 0xffffffff; error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, &rderr, NULL, NULL, p, cred); if (error) goto nfsmout; } if (bigenough && validentry) { if (nd->nd_flag & ND_NFSV4) { if (rderr) { dp->d_fileno = 0; } else if (gotmnton) { if (nfsva.na_mntonfileno != 0xffffffff) dp->d_fileno = nfsva.na_mntonfileno; else dp->d_fileno = nfsva.na_fileid; } else if (nfsva.na_filesid[0] == dnp->n_vattr.na_filesid[0] && nfsva.na_filesid[1] == dnp->n_vattr.na_filesid[1]) { dp->d_fileno = nfsva.na_fileid; } else { do { fakefileno--; } while (fakefileno == nfsva.na_fileid); dp->d_fileno = fakefileno; } } else { dp->d_fileno = fileno; } *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = ncookie.lval[0]; *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = ncookie.lval[1]; if (nfhp != NULL) { attr_ok = true; if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { - VREF(vp); + vref(vp); newvp = vp; unlocknewvp = 0; free(nfhp, M_NFSFH); np = dnp; } else if (isdotdot != 0) { /* * Skip doing a nfscl_nget() call for "..". * There's a race between acquiring the nfs * node here and lookups that look for the * directory being read (in the parent). * It would try to get a lock on ".." here, * owning the lock on the directory being * read. Lookup will hold the lock on ".." * and try to acquire the lock on the * directory being read. * If the directory is unlocked/relocked, * then there is a LOR with the buflock * vp is relocked. */ free(nfhp, M_NFSFH); } else { error = nfscl_nget(vp->v_mount, vp, nfhp, cnp, p, &np, LK_EXCLUSIVE); if (!error) { newvp = NFSTOV(np); unlocknewvp = 1; /* * If n_localmodtime >= time before RPC, * then a file modification operation, * such as VOP_SETATTR() of size, has * occurred while the Lookup RPC and * acquisition of the vnode happened. As * such, the attributes might be stale, * with possibly an incorrect size. */ NFSLOCKNODE(np); if (timespecisset( &np->n_localmodtime) && timespeccmp(&np->n_localmodtime, &ts, >=)) { NFSCL_DEBUG(4, "nfsrpc_readdirplus:" " localmod stale attributes\n"); attr_ok = false; } NFSUNLOCKNODE(np); } } nfhp = NULL; if (newvp != NULL) { if (attr_ok) error = nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 0); if (error) { if (unlocknewvp) vput(newvp); else vrele(newvp); goto nfsmout; } dp->d_type = vtonfs_dtype(np->n_vattr.na_type); ndp->ni_vp = newvp; NFSCNHASH(cnp, HASHINIT); if (cnp->cn_namelen <= NCHNAMLEN && ndp->ni_dvp != ndp->ni_vp && (newvp->v_type != VDIR || dctime.tv_sec != 0) && !named_dir) { cache_enter_time_flags(ndp->ni_dvp, ndp->ni_vp, cnp, &nfsva.na_ctime, newvp->v_type != VDIR ? NULL : &dctime, VFS_CACHE_DROPOLD); } if (unlocknewvp) vput(newvp); else vrele(newvp); newvp = NULL; } } } else if (nfhp != NULL) { free(nfhp, M_NFSFH); } NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); more_dirs = fxdr_unsigned(int, *tl); } /* * If at end of rpc data, get the eof boolean */ if (!more_dirs) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); eof = fxdr_unsigned(int, *tl); if (tryformoredirs) more_dirs = !eof; if (nd->nd_flag & ND_NFSV4) { error = nfscl_postop_attr(nd, nap, attrflagp); if (error) goto nfsmout; } } m_freem(nd->nd_mrep); nd->nd_mrep = NULL; } /* * Fill last record, iff any, out to a multiple of DIRBLKSIZ * by increasing d_reclen for the last record. */ if (blksiz > 0) { left = DIRBLKSIZ - blksiz; NFSBZERO(uiop->uio_iov->iov_base, left); dp->d_reclen += left; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + left; uiop->uio_iov->iov_len -= left; uiop->uio_resid -= left; uiop->uio_offset += left; } /* * If returning no data, assume end of file. * If not bigenough, return not end of file, since you aren't * returning all the data * Otherwise, return the eof flag from the server. */ if (eofp != NULL) { if (tresid == uiop->uio_resid) *eofp = 1; else if (!bigenough) *eofp = 0; else *eofp = eof; } /* * Add extra empty records to any remaining DIRBLKSIZ chunks. */ while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) { dp = (struct dirent *)uiop->uio_iov->iov_base; NFSBZERO(dp, DIRBLKSIZ); dp->d_type = DT_UNKNOWN; tl = (u_int32_t *)&dp->d_name[4]; *tl++ = cookie.lval[0]; *tl = cookie.lval[1]; dp->d_reclen = DIRBLKSIZ; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + DIRBLKSIZ; uiop->uio_iov->iov_len -= DIRBLKSIZ; uiop->uio_resid -= DIRBLKSIZ; uiop->uio_offset += DIRBLKSIZ; } nfsmout: if (nd->nd_mrep != NULL) m_freem(nd->nd_mrep); return (error); } /* * Nfs commit rpc */ int nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; nfsattrbit_t attrbits; int error; struct nfsmount *nmp = VFSTONFS(vp->v_mount); *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp, cred); NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); txdr_hyper(offset, tl); tl += 2; *tl = txdr_unsigned(cnt); if (nd->nd_flag & ND_NFSV4) { /* * And do a Getattr op. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); (void) nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, vp, p, cred); if (error) return (error); error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, NULL); if (!error && !nd->nd_repstat) { NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); NFSLOCKMNT(nmp); if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) { NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); nd->nd_repstat = NFSERR_STALEWRITEVERF; } NFSUNLOCKMNT(nmp); if (nd->nd_flag & ND_NFSV4) error = nfscl_postop_attr(nd, nap, attrflagp); } nfsmout: if (!error && nd->nd_repstat) error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * NFS byte range lock rpc. * (Mostly just calls one of the three lower level RPC routines.) */ int nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) { struct nfscllockowner *lp; struct nfsclclient *clp; struct nfsfh *nfhp; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp = VFSTONFS(vp->v_mount); u_int64_t off, len; off_t start, end; u_int32_t clidrev = 0; int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; int callcnt, dorpc; /* * Convert the flock structure into a start and end and do POSIX * bounds checking. */ switch (fl->l_whence) { case SEEK_SET: case SEEK_CUR: /* * Caller is responsible for adding any necessary offset * when SEEK_CUR is used. */ start = fl->l_start; off = fl->l_start; break; case SEEK_END: start = size + fl->l_start; off = size + fl->l_start; break; default: return (EINVAL); } if (start < 0) return (EINVAL); if (fl->l_len != 0) { end = start + fl->l_len - 1; if (end < start) return (EINVAL); } len = fl->l_len; if (len == 0) len = NFS64BITSSET; retrycnt = 0; do { nd->nd_repstat = 0; if (op == F_GETLK) { error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp); if (error) return (error); error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); if (!error) { clidrev = clp->nfsc_clientidrev; error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, p, id, flags); } else if (error == -1) { error = 0; } nfscl_clientrelease(clp); } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { /* * We must loop around for all lockowner cases. */ callcnt = 0; error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp); if (error) return (error); do { error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, clp, id, flags, &lp, &dorpc); /* * If it returns a NULL lp, we're done. */ if (lp == NULL) { if (callcnt == 0) nfscl_clientrelease(clp); else nfscl_releasealllocks(clp, vp, p, id, flags); return (error); } if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; else clidrev = 0; /* * If the server doesn't support Posix lock semantics, * only allow locks on the entire file, since it won't * handle overlapping byte ranges. * There might still be a problem when a lock * upgrade/downgrade (read<->write) occurs, since the * server "might" expect an unlock first? */ if (dorpc && (lp->nfsl_open->nfso_posixlock || (off == 0 && len == NFS64BITSSET))) { /* * Since the lock records will go away, we must * wait for grace and delay here. */ do { error = nfsrpc_locku(nd, nmp, lp, off, len, NFSV4LOCKT_READ, cred, p, 0); if ((nd->nd_repstat == NFSERR_GRACE || nd->nd_repstat == NFSERR_DELAY) && error == 0) (void) nfs_catnap(PZERO, (int)nd->nd_repstat, "nfs_advlock"); } while ((nd->nd_repstat == NFSERR_GRACE || nd->nd_repstat == NFSERR_DELAY) && error == 0); } callcnt++; } while (error == 0 && nd->nd_repstat == 0); nfscl_releasealllocks(clp, vp, p, id, flags); } else if (op == F_SETLK) { error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); if (error || donelocally) { return (error); } if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; else clidrev = 0; nfhp = VTONFS(vp)->n_fhp; if (!lp->nfsl_open->nfso_posixlock && (off != 0 || len != NFS64BITSSET)) { error = EINVAL; } else { error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, nfhp->nfh_len, lp, newone, reclaim, off, len, fl->l_type, cred, p, 0); } if (!error) error = nd->nd_repstat; nfscl_lockrelease(lp, error, newone); } else { error = EINVAL; } if (!error) error = nd->nd_repstat; if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || error == NFSERR_BADSESSION) { (void) nfs_catnap(PZERO, error, "nfs_advlock"); } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && clidrev != 0) { expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); retrycnt++; } } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && expireret == 0 && clidrev != 0 && retrycnt < 4)); if (error && retrycnt >= 4) error = EIO; return (error); } /* * The lower level routine for the LockT case. */ int nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, struct ucred *cred, NFSPROC_T *p, void *id, int flags) { u_int32_t *tl; int error, type, size; uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; struct nfsnode *np; struct nfsmount *nmp; struct nfsclsession *tsep; nmp = VFSTONFS(vp->v_mount); NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp, cred); NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); if (fl->l_type == F_RDLCK) *tl++ = txdr_unsigned(NFSV4LOCKT_READ); else *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); txdr_hyper(off, tl); tl += 2; txdr_hyper(len, tl); tl += 2; tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; *tl = tsep->nfsess_clientid.lval[1]; nfscl_filllockowner(id, own, flags); np = VTONFS(vp); NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], np->n_fhp->nfh_len); (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (nd->nd_repstat == 0) { fl->l_type = F_UNLCK; } else if (nd->nd_repstat == NFSERR_DENIED) { nd->nd_repstat = 0; fl->l_whence = SEEK_SET; NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); fl->l_start = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); tl += 2; if (len == NFS64BITSSET) fl->l_len = 0; else fl->l_len = len; type = fxdr_unsigned(int, *tl++); if (type == NFSV4LOCKT_WRITE) fl->l_type = F_WRLCK; else fl->l_type = F_RDLCK; /* * XXX For now, I have no idea what to do with the * conflicting lock_owner, so I'll just set the pid == 0 * and skip over the lock_owner. */ fl->l_pid = (pid_t)0; tl += 2; size = fxdr_unsigned(int, *tl); if (size < 0 || size > NFSV4_OPAQUELIMIT) error = EBADRPC; if (!error) error = nfsm_advance(nd, NFSM_RNDUP(size), -1); } else if (nd->nd_repstat == NFSERR_STALECLIENTID) nfscl_initiate_recovery(clp); nfsmout: m_freem(nd->nd_mrep); return (error); } /* * Lower level function that performs the LockU RPC. */ static int nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, struct nfscllockowner *lp, u_int64_t off, u_int64_t len, u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) { u_int32_t *tl; int error; nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(type); *tl = txdr_unsigned(lp->nfsl_seqid); if (nfstest_outofseq && (arc4random() % nfstest_outofseq) == 0) *tl = txdr_unsigned(lp->nfsl_seqid + 1); tl++; if (NFSHASNFSV4N(nmp)) *tl++ = 0; else *tl++ = lp->nfsl_stateid.seqid; *tl++ = lp->nfsl_stateid.other[0]; *tl++ = lp->nfsl_stateid.other[1]; *tl++ = lp->nfsl_stateid.other[2]; txdr_hyper(off, tl); tl += 2; txdr_hyper(len, tl); if (syscred) nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); NFSCL_INCRSEQID(lp->nfsl_seqid, nd); if (error) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); lp->nfsl_stateid.seqid = *tl++; lp->nfsl_stateid.other[0] = *tl++; lp->nfsl_stateid.other[1] = *tl++; lp->nfsl_stateid.other[2] = *tl; } else if (nd->nd_repstat == NFSERR_STALESTATEID) nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); nfsmout: m_freem(nd->nd_mrep); return (error); } /* * The actual Lock RPC. */ int nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, NFSPROC_T *p, int syscred) { u_int32_t *tl; int error, size; uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; struct nfsclsession *tsep; nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); if (type == F_RDLCK) *tl++ = txdr_unsigned(NFSV4LOCKT_READ); else *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); *tl++ = txdr_unsigned(reclaim); txdr_hyper(off, tl); tl += 2; txdr_hyper(len, tl); tl += 2; if (newone) { *tl = newnfs_true; NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2 * NFSX_UNSIGNED + NFSX_HYPER); *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); if (NFSHASNFSV4N(nmp)) *tl++ = 0; else *tl++ = lp->nfsl_open->nfso_stateid.seqid; *tl++ = lp->nfsl_open->nfso_stateid.other[0]; *tl++ = lp->nfsl_open->nfso_stateid.other[1]; *tl++ = lp->nfsl_open->nfso_stateid.other[2]; *tl++ = txdr_unsigned(lp->nfsl_seqid); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; *tl = tsep->nfsess_clientid.lval[1]; NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); } else { *tl = newnfs_false; NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); if (NFSHASNFSV4N(nmp)) *tl++ = 0; else *tl++ = lp->nfsl_stateid.seqid; *tl++ = lp->nfsl_stateid.other[0]; *tl++ = lp->nfsl_stateid.other[1]; *tl++ = lp->nfsl_stateid.other[2]; *tl = txdr_unsigned(lp->nfsl_seqid); if (nfstest_outofseq && (arc4random() % nfstest_outofseq) == 0) *tl = txdr_unsigned(lp->nfsl_seqid + 1); } if (syscred) nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error) return (error); if (newone) NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); NFSCL_INCRSEQID(lp->nfsl_seqid, nd); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); lp->nfsl_stateid.seqid = *tl++; lp->nfsl_stateid.other[0] = *tl++; lp->nfsl_stateid.other[1] = *tl++; lp->nfsl_stateid.other[2] = *tl; } else if (nd->nd_repstat == NFSERR_DENIED) { NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); size = fxdr_unsigned(int, *(tl + 7)); if (size < 0 || size > NFSV4_OPAQUELIMIT) error = EBADRPC; if (!error) error = nfsm_advance(nd, NFSM_RNDUP(size), -1); } else if (nd->nd_repstat == NFSERR_STALESTATEID) nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); nfsmout: m_freem(nd->nd_mrep); return (error); } /* * nfs statfs rpc * (always called with the vp for the mount point) */ int nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 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; struct nfsmount *nmp; nfsattrbit_t attrbits; int error; *attrflagp = 0; if (cloneblksizep != NULL) *cloneblksizep = 0; nmp = VFSTONFS(vp->v_mount); if (NFSHASNFSV4(nmp)) { /* * For V4, you actually do a getattr. */ NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred); if (leasep != NULL) NFSROOTFS_GETATTRBIT(&attrbits); else NFSSTATFS_GETATTRBIT(&attrbits); (void) nfsrv_putattrbit(nd, &attrbits); nd->nd_flag |= ND_USEGSSNAME; error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (nd->nd_repstat == 0) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL, NULL, cloneblksizep, p, cred); if (!error) { nmp->nm_fsid[0] = nap->na_filesid[0]; nmp->nm_fsid[1] = nap->na_filesid[1]; NFSSETHASSETFSID(nmp); *attrflagp = 1; } } else { error = nd->nd_repstat; } if (error) goto nfsmout; } else { NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp, NULL); error = nfscl_request(nd, vp, p, cred); if (error) return (error); if (nd->nd_flag & ND_NFSV3) { error = nfscl_postop_attr(nd, nap, attrflagp); if (error) goto nfsmout; } if (nd->nd_repstat) { error = nd->nd_repstat; goto nfsmout; } NFSM_DISSECT(tl, u_int32_t *, NFSX_STATFS(nd->nd_flag & ND_NFSV3)); } if (NFSHASNFSV3(nmp)) { sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; sbp->sf_abytes = fxdr_hyper(tl); tl += 2; sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; sbp->sf_afiles = fxdr_hyper(tl); tl += 2; sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); } else if (NFSHASNFSV4(nmp) == 0) { sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); } nfsmout: m_freem(nd->nd_mrep); return (error); } /* * nfs pathconf rpc */ int nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp, uint32_t *clone_blksizep, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) { struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp; u_int32_t *tl; nfsattrbit_t attrbits; int error; struct nfsnode *np; *has_namedattrp = false; *attrflagp = 0; *clone_blksizep = 0; nmp = VFSTONFS(vp->v_mount); if (NFSHASNFSV4(nmp)) { np = VTONFS(vp); if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 && nmp->nm_fhsize == 0) { /* Attempt to get the actual root file handle. */ error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, p); if (error != 0) return (EACCES); if (np->n_fhp->nfh_len == NFSX_FHMAX + 1) nfscl_statfs(vp, cred, p); } /* * For V4, you actually do a getattr. */ NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred); NFSPATHCONF_GETATTRBIT(&attrbits); (void) nfsrv_putattrbit(nd, &attrbits); nd->nd_flag |= ND_USEGSSNAME; error = nfscl_request(nd, vp, p, cred); if (error) return (error); 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, clone_blksizep, p, cred); if (!error) *attrflagp = 1; } else { error = nd->nd_repstat; } } else { NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp, NULL); error = nfscl_request(nd, vp, p, cred); if (error) return (error); error = nfscl_postop_attr(nd, nap, attrflagp); if (nd->nd_repstat && !error) error = nd->nd_repstat; if (!error) { NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); pc->pc_chownrestricted = fxdr_unsigned(u_int32_t, *tl++); pc->pc_caseinsensitive = fxdr_unsigned(u_int32_t, *tl++); pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); } } nfsmout: m_freem(nd->nd_mrep); return (error); } /* * nfs version 3 fsinfo rpc call */ int nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; int error; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp, NULL); error = nfscl_request(nd, vp, p, cred); if (error) return (error); error = nfscl_postop_attr(nd, nap, attrflagp); if (nd->nd_repstat && !error) error = nd->nd_repstat; if (!error) { NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); fsp->fs_maxfilesize = fxdr_hyper(tl); tl += 2; fxdr_nfsv3time(tl, &fsp->fs_timedelta); tl += 2; fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); } nfsmout: m_freem(nd->nd_mrep); return (error); } /* * This function performs the Renew RPC. */ int nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred, NFSPROC_T *p) { u_int32_t *tl; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; struct nfsmount *nmp; int error; struct nfssockreq *nrp; struct nfsclsession *tsep; nmp = clp->nfsc_nmp; if (nmp == NULL) return (0); if (dsp == NULL) nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0, 0, cred); else nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, &dsp->nfsclds_sess, 0, 0, NULL); if (!NFSHASNFSV4N(nmp)) { /* NFSv4.1 just uses a Sequence Op and not a Renew. */ NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; *tl = tsep->nfsess_clientid.lval[1]; } nrp = NULL; if (dsp != NULL) nrp = dsp->nfsclds_sockp; if (nrp == NULL) /* If NULL, use the MDS socket. */ nrp = &nmp->nm_sockreq; nd->nd_flag |= ND_USEGSSNAME; if (dsp == NULL) error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); else { error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); if (error == ENXIO) nfscl_cancelreqs(dsp); } if (error) return (error); error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * This function performs the Releaselockowner RPC. */ int nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) { struct nfsrv_descript nfsd, *nd = &nfsd; u_int32_t *tl; int error; uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; struct nfsclsession *tsep; if (NFSHASNFSV4N(nmp)) { /* For NFSv4.1, do a FreeStateID. */ nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL, NULL, 0, 0, cred); nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID); } else { nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL, NULL, 0, 0, NULL); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; *tl = tsep->nfsess_clientid.lval[1]; NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); } nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error) return (error); error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * This function performs the Compound to get the mount pt FH. */ int nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, NFSPROC_T *p) { u_int32_t *tl; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; u_char *cp, *cp2, *fhp; int error, cnt, len, setnil; u_int32_t *opcntp; nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0, 0, NULL); cp = dirpath; cnt = 0; do { setnil = 0; while (*cp == '/') cp++; cp2 = cp; while (*cp2 != '\0' && *cp2 != '/') cp2++; if (*cp2 == '/') { setnil = 1; *cp2 = '\0'; } if (cp2 != cp) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_LOOKUP); nfsm_strtom(nd, cp, strlen(cp)); cnt++; } if (setnil) *cp2++ = '/'; cp = cp2; } while (*cp != '\0'); if (NFSHASNFSV4N(nmp)) /* Has a Sequence Op done by nfscl_reqstart(). */ *opcntp = txdr_unsigned(3 + cnt); else *opcntp = txdr_unsigned(2 + cnt); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETFH); nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); tl += (2 + 2 * cnt); if ((len = fxdr_unsigned(int, *tl)) <= 0 || len > NFSX_FHMAX) { nd->nd_repstat = NFSERR_BADXDR; } else { fhp = malloc(len + 1, M_TEMP, M_WAITOK); nd->nd_repstat = nfsrv_mtostr(nd, fhp, len); if (nd->nd_repstat == 0) { NFSLOCKMNT(nmp); if (nmp->nm_fhsize == 0) { NFSBCOPY(fhp, nmp->nm_fh, len); nmp->nm_fhsize = len; } NFSUNLOCKMNT(nmp); } free(fhp, M_TEMP); } } error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * This function performs the Delegreturn RPC. */ int nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, struct nfsmount *nmp, NFSPROC_T *p, int syscred) { u_int32_t *tl; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; int error; nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, dp->nfsdl_fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); if (NFSHASNFSV4N(nmp)) *tl++ = 0; else *tl++ = dp->nfsdl_stateid.seqid; *tl++ = dp->nfsdl_stateid.other[0]; *tl++ = dp->nfsdl_stateid.other[1]; *tl = dp->nfsdl_stateid.other[2]; if (syscred) nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error) return (error); error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * nfs getacl call. */ int nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp) { struct nfsrv_descript nfsd, *nd = &nfsd; int error; nfsattrbit_t attrbits; struct nfsmount *nmp = VFSTONFS(vp->v_mount); if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) return (EOPNOTSUPP); NFSCL_REQSTART(nd, NFSPROC_GETACL, vp, cred); NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); (void) nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, p, cred); if (error) 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, NULL, p, cred); else error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * nfs setacl call. */ int nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp) { int error; struct nfsmount *nmp = VFSTONFS(vp->v_mount); if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) return (EOPNOTSUPP); error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL); return (error); } /* * nfs setacl call. */ static int nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp, nfsv4stateid_t *stateidp) { struct nfsrv_descript nfsd, *nd = &nfsd; int error; nfsattrbit_t attrbits; struct nfsmount *nmp = VFSTONFS(vp->v_mount); if (!NFSHASNFSV4(nmp)) return (EOPNOTSUPP); NFSCL_REQSTART(nd, NFSPROC_SETACL, vp, cred); nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); NFSZERO_ATTRBIT(&attrbits); 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, 0); error = nfscl_request(nd, vp, p, cred); if (error) return (error); /* Don't care about the pre/postop attributes */ m_freem(nd->nd_mrep); return (nd->nd_repstat); } /* * Do the NFSv4.1 Exchange ID. */ int nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp, struct nfssockreq *nrp, int minorvers, uint32_t exchflags, struct nfsclds **dspp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl, v41flags; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; struct nfsclds *dsp; struct timespec verstime; int error, len; *dspp = NULL; if (minorvers == 0) minorvers = nmp->nm_minorvers; nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL, NFS_VER4, minorvers, NULL); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */ *tl = txdr_unsigned(clp->nfsc_rev); (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(exchflags); *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* Set the implementation id4 */ *tl = txdr_unsigned(1); (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); (void) nfsm_strtom(nd, version, strlen(version)); NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ verstime.tv_nsec = 0; txdr_nfsv4time(&verstime, tl); nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error, (int)nd->nd_repstat); if (error != 0) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER); len = fxdr_unsigned(int, *(tl + 7)); if (len < 0 || len > NFSV4_OPAQUELIMIT) { error = NFSERR_BADXDR; goto nfsmout; } dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS, M_WAITOK | M_ZERO); dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; dsp->nfsclds_servownlen = len; dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++; dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++; dsp->nfsclds_sess.nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); v41flags = fxdr_unsigned(uint32_t, *tl); if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 && NFSHASPNFSOPT(nmp)) { NFSCL_DEBUG(1, "set PNFS\n"); NFSLOCKMNT(nmp); nmp->nm_state |= NFSSTA_PNFS; NFSUNLOCKMNT(nmp); dsp->nfsclds_flags |= NFSCLDS_MDS; } if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0) dsp->nfsclds_flags |= NFSCLDS_DS; if (minorvers == NFSV42_MINORVERSION) dsp->nfsclds_flags |= NFSCLDS_MINORV2; if (len > 0) nd->nd_repstat = nfsrv_mtostr(nd, dsp->nfsclds_serverown, len); if (nd->nd_repstat == 0) { mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF); nfscl_initsessionslots(&dsp->nfsclds_sess); *dspp = dsp; } else free(dsp, M_NFSCLDS); } error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * Do the NFSv4.1 Create Session. */ int nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep, struct nfssockreq *nrp, struct nfsclds *dsp, uint32_t sequenceid, int mds, struct ucred *cred, NFSPROC_T *p) { uint32_t crflags, maxval, *tl; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; int error, irdcnt, minorvers; /* Make sure nm_rsize, nm_wsize is set. */ if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0) nmp->nm_rsize = NFS_MAXBSIZE; if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0) nmp->nm_wsize = NFS_MAXBSIZE; if (dsp == NULL) minorvers = nmp->nm_minorvers; else if ((dsp->nfsclds_flags & NFSCLDS_MINORV2) != 0) minorvers = NFSV42_MINORVERSION; else minorvers = NFSV41_MINORVERSION; nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL, NFS_VER4, minorvers, NULL); NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); *tl++ = sep->nfsess_clientid.lval[0]; *tl++ = sep->nfsess_clientid.lval[1]; *tl++ = txdr_unsigned(sequenceid); crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST); if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0) crflags |= NFSV4CRSESS_CONNBACKCHAN; *tl = txdr_unsigned(crflags); /* Fill in fore channel attributes. */ NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); *tl++ = 0; /* Header pad size */ if ((nd->nd_flag & ND_NFSV42) != 0 && mds != 0 && sb_max_adj >= nmp->nm_wsize && sb_max_adj >= nmp->nm_rsize) { /* * NFSv4.2 Extended Attribute operations may want to do * requests/replies that are larger than nm_rsize/nm_wsize. */ *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR); *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR); } else { *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR); *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR); } *tl++ = txdr_unsigned(4096); /* Max response size cached */ *tl++ = txdr_unsigned(20); /* Max operations */ *tl++ = txdr_unsigned(64); /* Max slots */ *tl = 0; /* No rdma ird */ /* Fill in back channel attributes. */ NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); *tl++ = 0; /* Header pad size */ *tl++ = txdr_unsigned(10000); /* Max request size */ *tl++ = txdr_unsigned(10000); /* Max response size */ *tl++ = txdr_unsigned(4096); /* Max response size cached */ *tl++ = txdr_unsigned(4); /* Max operations */ *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */ *tl = 0; /* No rdma ird */ NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */ /* Allow AUTH_SYS callbacks as uid, gid == 0. */ *tl++ = txdr_unsigned(1); /* Auth_sys only */ *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */ *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */ *tl++ = 0; /* Null machine name */ *tl++ = 0; /* Uid == 0 */ *tl++ = 0; /* Gid == 0 */ *tl = 0; /* No additional gids */ nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID); tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); crflags = fxdr_unsigned(uint32_t, *tl); if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) { NFSLOCKMNT(nmp); nmp->nm_state |= NFSSTA_SESSPERSIST; NFSUNLOCKMNT(nmp); } /* Get the fore channel slot count. */ NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); tl++; /* Skip the header pad size. */ /* Make sure nm_wsize is small enough. */ maxval = fxdr_unsigned(uint32_t, *tl++); while (maxval < nmp->nm_wsize + NFS_MAXXDR) { if (nmp->nm_wsize > 8096) nmp->nm_wsize /= 2; else break; } sep->nfsess_maxreq = maxval; /* Make sure nm_rsize is small enough. */ maxval = fxdr_unsigned(uint32_t, *tl++); while (maxval < nmp->nm_rsize + NFS_MAXXDR) { if (nmp->nm_rsize > 8096) nmp->nm_rsize /= 2; else break; } sep->nfsess_maxresp = maxval; sep->nfsess_maxcache = fxdr_unsigned(int, *tl++); tl++; sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++); NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots); irdcnt = fxdr_unsigned(int, *tl); if (irdcnt < 0 || irdcnt > 1) { error = NFSERR_BADXDR; goto nfsmout; } if (irdcnt > 0) NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED); /* and the back channel slot count. */ NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); tl += 5; sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl); NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots); } error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * Do the NFSv4.1 Destroy Client. */ int nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; int error; struct nfsclsession *tsep; nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0, 0, NULL); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; *tl = tsep->nfsess_clientid.lval[1]; nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * Do the NFSv4.1 LayoutGet. */ static int nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode, uint64_t offset, uint64_t len, uint64_t minlen, int layouttype, int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p) { struct nfsrv_descript nfsd, *nd = &nfsd; int error; nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0, 0, cred); nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, layouttype, layoutlen, 0); nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); if (error != 0) return (error); if (nd->nd_repstat == 0) error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep, flhp); if (error == 0 && nd->nd_repstat != 0) error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * Do the NFSv4.1 Get Device Info. */ int nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype, uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred, NFSPROC_T *p) { uint32_t cnt, *tl, vers, minorvers; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; struct sockaddr_in sin, ssin; struct sockaddr_in6 sin6, ssin6; struct nfsclds *dsp = NULL, **dspp, **gotdspp; struct nfscldevinfo *ndi; int addrcnt = 0, bitcnt, error, gotminor, gotvers, i, isudp, j; int stripecnt; uint8_t stripeindex; sa_family_t af, safilled; ssin.sin_port = 0; /* To shut up compiler. */ ssin.sin_addr.s_addr = 0; /* ditto */ *ndip = NULL; ndi = NULL; gotdspp = NULL; nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID); tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); *tl++ = txdr_unsigned(layouttype); *tl++ = txdr_unsigned(100000); if (notifybitsp != NULL && *notifybitsp != 0) { *tl = txdr_unsigned(1); /* One word of bits. */ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(*notifybitsp); } else *tl = txdr_unsigned(0); nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (layouttype != fxdr_unsigned(int, *tl)) printf("EEK! devinfo layout type not same!\n"); if (layouttype == NFSLAYOUT_NFSV4_1_FILES) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); stripecnt = fxdr_unsigned(int, *tl); NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt); if (stripecnt < 1 || stripecnt > 4096) { printf("pNFS File layout devinfo stripecnt %d:" " out of range\n", stripecnt); error = NFSERR_BADXDR; goto nfsmout; } NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED); addrcnt = fxdr_unsigned(int, *(tl + stripecnt)); NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt); if (addrcnt < 1 || addrcnt > 128) { printf("NFS devinfo addrcnt %d: out of range\n", addrcnt); error = NFSERR_BADXDR; goto nfsmout; } /* * Now we know how many stripe indices and addresses, so * we can allocate the structure the correct size. */ i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *) + 1; NFSCL_DEBUG(4, "stripeindices=%d\n", i); ndi = malloc(sizeof(*ndi) + (addrcnt + i) * sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO); NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID); ndi->nfsdi_refcnt = 0; ndi->nfsdi_flags = NFSDI_FILELAYOUT; ndi->nfsdi_stripecnt = stripecnt; ndi->nfsdi_addrcnt = addrcnt; /* Fill in the stripe indices. */ for (i = 0; i < stripecnt; i++) { stripeindex = fxdr_unsigned(uint8_t, *tl++); NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex); if (stripeindex >= addrcnt) { printf("pNFS File Layout devinfo" " stripeindex %d: too big\n", (int)stripeindex); error = NFSERR_BADXDR; goto nfsmout; } nfsfldi_setstripeindex(ndi, i, stripeindex); } } else if (layouttype == NFSLAYOUT_FLEXFILE) { /* For Flex File, we only get one address list. */ ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO); NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID); ndi->nfsdi_refcnt = 0; ndi->nfsdi_flags = NFSDI_FLEXFILE; addrcnt = ndi->nfsdi_addrcnt = 1; } /* Now, dissect the server address(es). */ safilled = AF_UNSPEC; for (i = 0; i < addrcnt; i++) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); cnt = fxdr_unsigned(uint32_t, *tl); if (cnt == 0) { printf("NFS devinfo 0 len addrlist\n"); error = NFSERR_BADXDR; goto nfsmout; } dspp = nfsfldi_addr(ndi, i); safilled = AF_UNSPEC; for (j = 0; j < cnt; j++) { error = nfsv4_getipaddr(nd, &sin, &sin6, &af, &isudp); if (error != 0 && error != EPERM) { error = NFSERR_BADXDR; goto nfsmout; } if (error == 0 && isudp == 0) { /* * The priority is: * - Same address family. * Save the address and dspp, so that * the connection can be done after * parsing is complete. */ if (safilled == AF_UNSPEC || (af == nmp->nm_nam->sa_family && safilled != nmp->nm_nam->sa_family) ) { if (af == AF_INET) ssin = sin; else ssin6 = sin6; safilled = af; gotdspp = dspp; } } } } gotvers = NFS_VER4; /* Default NFSv4.1 for File Layout. */ gotminor = NFSV41_MINORVERSION; /* For Flex File, we will take one of the versions to use. */ if (layouttype == NFSLAYOUT_FLEXFILE) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); j = fxdr_unsigned(int, *tl); if (j < 1 || j > NFSDEV_MAXVERS) { printf("pNFS: too many versions\n"); error = NFSERR_BADXDR; goto nfsmout; } gotvers = 0; gotminor = 0; for (i = 0; i < j; i++) { NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED); vers = fxdr_unsigned(uint32_t, *tl++); minorvers = fxdr_unsigned(uint32_t, *tl++); if (vers == NFS_VER3) minorvers = 0; if ((vers == NFS_VER4 && ((minorvers == NFSV41_MINORVERSION && gotminor == 0) || minorvers == NFSV42_MINORVERSION)) || (vers == NFS_VER3 && gotvers == 0)) { gotvers = vers; gotminor = minorvers; /* We'll take this one. */ ndi->nfsdi_versindex = i; ndi->nfsdi_vers = vers; ndi->nfsdi_minorvers = minorvers; ndi->nfsdi_rsize = fxdr_unsigned( uint32_t, *tl++); ndi->nfsdi_wsize = fxdr_unsigned( uint32_t, *tl++); if (*tl == newnfs_true) ndi->nfsdi_flags |= NFSDI_TIGHTCOUPLED; else ndi->nfsdi_flags &= ~NFSDI_TIGHTCOUPLED; } } if (gotvers == 0) { printf("pNFS: no NFSv3, NFSv4.1 or NFSv4.2\n"); error = NFSERR_BADXDR; goto nfsmout; } } /* And the notify bits. */ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); bitcnt = fxdr_unsigned(int, *tl); if (bitcnt > 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); if (notifybitsp != NULL) *notifybitsp = fxdr_unsigned(uint32_t, *tl); } if (safilled != AF_UNSPEC) { KASSERT(ndi != NULL, ("ndi is NULL")); *ndip = ndi; } else error = EPERM; if (error == 0) { /* * Now we can do a TCP connection for the correct * NFS version and IP address. */ error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled, gotvers, gotminor, &dsp, p); } if (error == 0) { KASSERT(gotdspp != NULL, ("gotdspp is NULL")); *gotdspp = dsp; } } if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; nfsmout: if (error != 0 && ndi != NULL) nfscl_freedevinfo(ndi); m_freem(nd->nd_mrep); return (error); } /* * Do the NFSv4.1 LayoutCommit. */ int nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp, int layouttype, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; int error; nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER + NFSX_STATEID); txdr_hyper(off, tl); tl += 2; txdr_hyper(len, tl); tl += 2; if (reclaim != 0) *tl++ = newnfs_true; else *tl++ = newnfs_false; *tl++ = txdr_unsigned(stateidp->seqid); *tl++ = stateidp->other[0]; *tl++ = stateidp->other[1]; *tl++ = stateidp->other[2]; *tl++ = newnfs_true; if (lastbyte < off) lastbyte = off; else if (lastbyte >= (off + len)) lastbyte = off + len - 1; txdr_hyper(lastbyte, tl); tl += 2; *tl++ = newnfs_false; *tl++ = txdr_unsigned(layouttype); /* All supported layouts are 0 length. */ *tl = txdr_unsigned(0); nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * Do the NFSv4.1 LayoutReturn. */ int nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, uint32_t stat, uint32_t op, char *devid) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; uint64_t tu64; int error; nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); if (reclaim != 0) *tl++ = newnfs_true; else *tl++ = newnfs_false; *tl++ = txdr_unsigned(layouttype); *tl++ = txdr_unsigned(iomode); *tl = txdr_unsigned(layoutreturn); if (layoutreturn == NFSLAYOUTRETURN_FILE) { NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + NFSX_UNSIGNED); txdr_hyper(offset, tl); tl += 2; txdr_hyper(len, tl); tl += 2; NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid); *tl++ = txdr_unsigned(stateidp->seqid); *tl++ = stateidp->other[0]; *tl++ = stateidp->other[1]; *tl++ = stateidp->other[2]; if (layouttype == NFSLAYOUT_NFSV4_1_FILES) *tl = txdr_unsigned(0); else if (layouttype == NFSLAYOUT_FLEXFILE) { if (stat != 0) { *tl = txdr_unsigned(2 * NFSX_HYPER + NFSX_STATEID + NFSX_V4DEVICEID + 5 * NFSX_UNSIGNED); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + NFSX_V4DEVICEID + 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(1); /* One error. */ tu64 = 0; /* Offset. */ txdr_hyper(tu64, tl); tl += 2; tu64 = UINT64_MAX; /* Length. */ txdr_hyper(tu64, tl); tl += 2; NFSBCOPY(stateidp, tl, NFSX_STATEID); tl += (NFSX_STATEID / NFSX_UNSIGNED); *tl++ = txdr_unsigned(1); /* One error. */ NFSBCOPY(devid, tl, NFSX_V4DEVICEID); tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); *tl++ = txdr_unsigned(stat); *tl++ = txdr_unsigned(op); } else { *tl = txdr_unsigned(2 * NFSX_UNSIGNED); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); /* No ioerrs. */ *tl++ = 0; } *tl = 0; /* No stats yet. */ } } nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); if (*tl != 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); stateidp->other[0] = *tl++; stateidp->other[1] = *tl++; stateidp->other[2] = *tl; } } else error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * Do the NFSv4.2 LayoutError. */ static int nfsrpc_layouterror(struct nfsmount *nmp, uint8_t *fh, int fhlen, uint64_t offset, uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, uint32_t stat, uint32_t op, char *devid) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; int error; nfscl_reqstart(nd, NFSPROC_LAYOUTERROR, nmp, fh, fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); txdr_hyper(offset, tl); tl += 2; txdr_hyper(len, tl); tl += 2; *tl++ = txdr_unsigned(stateidp->seqid); *tl++ = stateidp->other[0]; *tl++ = stateidp->other[1]; *tl++ = stateidp->other[2]; *tl++ = txdr_unsigned(1); NFSBCOPY(devid, tl, NFSX_V4DEVICEID); tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); *tl++ = txdr_unsigned(stat); *tl = txdr_unsigned(op); nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); if (nd->nd_repstat != 0) error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * Acquire a layout and devinfo, if possible. The caller must have acquired * a reference count on the nfsclclient structure before calling this. * Return the layout in lypp with a reference count on it, if successful. */ static int nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, int iomode, uint32_t rw, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off, struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) { struct nfscllayout *lyp; struct nfsclflayout *flp; struct nfsclflayouthead flh; int error = 0, islocked, layoutlen, layouttype, recalled, retonclose; nfsv4stateid_t stateid; struct nfsclsession *tsep; *lypp = NULL; if (NFSHASFLEXFILE(nmp)) layouttype = NFSLAYOUT_FLEXFILE; else layouttype = NFSLAYOUT_NFSV4_1_FILES; /* * If lyp is returned non-NULL, there will be a refcnt (shared lock) * on it, iff flp != NULL or a lock (exclusive lock) on it iff * flp == NULL. */ lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, off, rw, &flp, &recalled); islocked = 0; if (lyp == NULL || flp == NULL) { if (recalled != 0) return (EIO); LIST_INIT(&flh); tsep = nfsmnt_mdssession(nmp); layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); if (lyp == NULL) { stateid.seqid = 0; stateid.other[0] = stateidp->other[0]; stateid.other[1] = stateidp->other[1]; stateid.other[2] = stateidp->other[2]; error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX, (uint64_t)0, layouttype, layoutlen, &stateid, &retonclose, &flh, cred, p); } else { islocked = 1; stateid.seqid = lyp->nfsly_stateid.seqid; stateid.other[0] = lyp->nfsly_stateid.other[0]; stateid.other[1] = lyp->nfsly_stateid.other[1]; stateid.other[2] = lyp->nfsly_stateid.other[2]; error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, nfhp->nfh_len, iomode, off, UINT64_MAX, (uint64_t)0, layouttype, layoutlen, &stateid, &retonclose, &flh, cred, p); } error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, &flh, layouttype, error, NULL, cred, p); if (error == 0) *lypp = lyp; else if (islocked != 0) nfscl_rellayout(lyp, 1); } else *lypp = lyp; return (error); } /* * Do a TCP connection plus exchange id and create session. * If successful, a "struct nfsclds" is linked into the list for the * mount point and a pointer to it is returned. */ static int nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin, struct sockaddr_in6 *sin6, sa_family_t af, int vers, int minorvers, struct nfsclds **dspp, NFSPROC_T *p) { struct sockaddr_in *msad, *sad; struct sockaddr_in6 *msad6, *sad6; struct nfsclclient *clp; struct nfssockreq *nrp; struct nfsclds *dsp, *tdsp; int error, firsttry; enum nfsclds_state retv; uint32_t sequenceid = 0; KASSERT(nmp->nm_sockreq.nr_cred != NULL, ("nfsrpc_fillsa: NULL nr_cred")); NFSLOCKCLSTATE(); clp = nmp->nm_clp; NFSUNLOCKCLSTATE(); if (clp == NULL) return (EPERM); if (af == AF_INET) { NFSLOCKMNT(nmp); /* * Check to see if we already have a session for this * address that is usable for a DS. * Note that the MDS's address is in a different place * than the sessions already acquired for DS's. */ msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam; tdsp = TAILQ_FIRST(&nmp->nm_sess); while (tdsp != NULL) { if (msad != NULL && msad->sin_family == AF_INET && sin->sin_addr.s_addr == msad->sin_addr.s_addr && sin->sin_port == msad->sin_port && (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && tdsp->nfsclds_sess.nfsess_defunct == 0) { *dspp = tdsp; NFSUNLOCKMNT(nmp); NFSCL_DEBUG(4, "fnd same addr\n"); return (0); } tdsp = TAILQ_NEXT(tdsp, nfsclds_list); if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) msad = (struct sockaddr_in *) tdsp->nfsclds_sockp->nr_nam; else msad = NULL; } NFSUNLOCKMNT(nmp); /* No IP address match, so look for new/trunked one. */ sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO); sad->sin_len = sizeof(*sad); sad->sin_family = AF_INET; sad->sin_port = sin->sin_port; sad->sin_addr.s_addr = sin->sin_addr.s_addr; if (NFSHASPNFS(nmp) && NFSHASKERB(nmp)) { /* For pNFS, a separate server principal is needed. */ nrp = malloc(sizeof(*nrp) + NI_MAXSERV + NI_MAXHOST, M_NFSSOCKREQ, M_WAITOK | M_ZERO); /* * Use the latter part of nr_srvprinc as a temporary * buffer for the IP address. */ inet_ntoa_r(sad->sin_addr, &nrp->nr_srvprinc[NI_MAXSERV]); NFSCL_DEBUG(1, "nfsrpc_fillsa: DS IP=%s\n", &nrp->nr_srvprinc[NI_MAXSERV]); if (!rpc_gss_ip_to_srv_principal_call( &nrp->nr_srvprinc[NI_MAXSERV], "nfs", nrp->nr_srvprinc)) nrp->nr_srvprinc[0] = '\0'; NFSCL_DEBUG(1, "nfsrpc_fillsa: srv principal=%s\n", nrp->nr_srvprinc); } else nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); nrp->nr_nam = (struct sockaddr *)sad; } else if (af == AF_INET6) { NFSLOCKMNT(nmp); /* * Check to see if we already have a session for this * address that is usable for a DS. * Note that the MDS's address is in a different place * than the sessions already acquired for DS's. */ msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam; tdsp = TAILQ_FIRST(&nmp->nm_sess); while (tdsp != NULL) { if (msad6 != NULL && msad6->sin6_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &msad6->sin6_addr) && sin6->sin6_port == msad6->sin6_port && (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && tdsp->nfsclds_sess.nfsess_defunct == 0) { *dspp = tdsp; NFSUNLOCKMNT(nmp); return (0); } tdsp = TAILQ_NEXT(tdsp, nfsclds_list); if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) msad6 = (struct sockaddr_in6 *) tdsp->nfsclds_sockp->nr_nam; else msad6 = NULL; } NFSUNLOCKMNT(nmp); /* No IP address match, so look for new/trunked one. */ sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO); sad6->sin6_len = sizeof(*sad6); sad6->sin6_family = AF_INET6; sad6->sin6_port = sin6->sin6_port; NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr, sizeof(struct in6_addr)); if (NFSHASPNFS(nmp) && NFSHASKERB(nmp)) { /* For pNFS, a separate server principal is needed. */ nrp = malloc(sizeof(*nrp) + NI_MAXSERV + NI_MAXHOST, M_NFSSOCKREQ, M_WAITOK | M_ZERO); /* * Use the latter part of nr_srvprinc as a temporary * buffer for the IP address. */ inet_ntop(AF_INET6, &sad6->sin6_addr, &nrp->nr_srvprinc[NI_MAXSERV], NI_MAXHOST); NFSCL_DEBUG(1, "nfsrpc_fillsa: DS IP=%s\n", &nrp->nr_srvprinc[NI_MAXSERV]); if (!rpc_gss_ip_to_srv_principal_call( &nrp->nr_srvprinc[NI_MAXSERV], "nfs", nrp->nr_srvprinc)) nrp->nr_srvprinc[0] = '\0'; NFSCL_DEBUG(1, "nfsrpc_fillsa: srv principal=%s\n", nrp->nr_srvprinc); } else nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); nrp->nr_nam = (struct sockaddr *)sad6; } else return (EPERM); nrp->nr_sotype = SOCK_STREAM; mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF); nrp->nr_prog = NFS_PROG; nrp->nr_vers = vers; /* * Use the credentials that were used for the mount, which are * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc. * Ref. counting the credentials with crhold() is probably not * necessary, since nm_sockreq.nr_cred won't be crfree()'d until * unmount, but I did it anyhow. */ nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred); error = newnfs_connect(nmp, nrp, NULL, p, 0, false, &nrp->nr_client); NFSCL_DEBUG(3, "DS connect=%d\n", error); dsp = NULL; /* Now, do the exchangeid and create session. */ if (error == 0) { if (vers == NFS_VER4) { firsttry = 0; do { error = nfsrpc_exchangeid(nmp, clp, nrp, minorvers, NFSV4EXCH_USEPNFSDS, &dsp, nrp->nr_cred, p); NFSCL_DEBUG(3, "DS exchangeid=%d\n", error); if (error == NFSERR_MINORVERMISMATCH) minorvers = NFSV42_MINORVERSION; } while (error == NFSERR_MINORVERMISMATCH && firsttry++ == 0); if (error != 0) newnfs_disconnect(NULL, nrp); } else { dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO); dsp->nfsclds_flags |= NFSCLDS_DS; dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */ mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF); } } if (error == 0) { dsp->nfsclds_sockp = nrp; if (vers == NFS_VER4) { NFSLOCKMNT(nmp); retv = nfscl_getsameserver(nmp, dsp, &tdsp, &sequenceid); NFSCL_DEBUG(3, "getsame ret=%d\n", retv); if (retv == NFSDSP_USETHISSESSION && nfscl_dssameconn != 0) { NFSLOCKDS(tdsp); tdsp->nfsclds_flags |= NFSCLDS_SAMECONN; NFSUNLOCKDS(tdsp); NFSUNLOCKMNT(nmp); /* * If there is already a session for this * server, use it. */ newnfs_disconnect(NULL, nrp); nfscl_freenfsclds(dsp); *dspp = tdsp; return (0); } if (retv == NFSDSP_NOTFOUND) sequenceid = dsp->nfsclds_sess.nfsess_sequenceid; NFSUNLOCKMNT(nmp); error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, nrp, dsp, sequenceid, 0, nrp->nr_cred, p); NFSCL_DEBUG(3, "DS createsess=%d\n", error); } } else { NFSFREECRED(nrp->nr_cred); NFSFREEMUTEX(&nrp->nr_mtx); free(nrp->nr_nam, M_SONAME); free(nrp, M_NFSSOCKREQ); } if (error == 0) { NFSCL_DEBUG(3, "add DS session\n"); /* * Put it at the end of the list. That way the list * is ordered by when the entry was added. This matters * since the one done first is the one that should be * used for sequencid'ing any subsequent create sessions. */ NFSLOCKMNT(nmp); TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list); NFSUNLOCKMNT(nmp); *dspp = dsp; } else if (dsp != NULL) { newnfs_disconnect(NULL, nrp); nfscl_freenfsclds(dsp); } return (error); } /* * Do the NFSv4.1 Reclaim Complete. */ int nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; int error; nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = newnfs_false; nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * Initialize the slot tables for a session. */ static void nfscl_initsessionslots(struct nfsclsession *sep) { int i; for (i = 0; i < NFSV4_CBSLOTS; i++) { if (sep->nfsess_cbslots[i].nfssl_reply != NULL) m_freem(sep->nfsess_cbslots[i].nfssl_reply); NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot)); } for (i = 0; i < 64; i++) sep->nfsess_slotseq[i] = 0; sep->nfsess_slots = 0; sep->nfsess_badslots = 0; } /* * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS). */ int nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p) { struct nfsnode *np = VTONFS(vp); struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfscllayout *layp; struct nfscldevinfo *dip; struct nfsclflayout *rflp; struct mbuf *m, *m2; struct nfsclwritedsdorpc *drpc, *tdrpc; nfsv4stateid_t stateid; struct ucred *newcred; uint64_t lastbyte, len, off, oresid, xfer; int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo; void *lckp; uint8_t *dev; void *iovbase = NULL; size_t iovlen = 0; off_t offs = 0; ssize_t resid = 0; uint32_t op; if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || (np->n_flag & NNOLAYOUT) != 0) return (EIO); /* Now, get a reference cnt on the clientid for this mount. */ if (nfscl_getref(nmp) == 0) return (EIO); /* Find an appropriate stateid. */ newcred = NFSNEWCRED(cred); error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, rwaccess, 1, newcred, p, &stateid, &lckp); if (error != 0) { NFSFREECRED(newcred); nfscl_relref(nmp); return (error); } /* Search for a layout for this file. */ off = uiop->uio_offset; layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, off, rwaccess, &rflp, &recalled); if (layp == NULL || rflp == NULL) { if (recalled != 0) { NFSFREECRED(newcred); if (lckp != NULL) nfscl_lockderef(lckp); nfscl_relref(nmp); return (EIO); } if (layp != NULL) { nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0); layp = NULL; } /* Try and get a Layout, if it is supported. */ if (rwaccess == NFSV4OPEN_ACCESSWRITE || (np->n_flag & NWRITEOPENED) != 0) iolaymode = NFSLAYOUTIOMODE_RW; else iolaymode = NFSLAYOUTIOMODE_READ; error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, rwaccess, NULL, &stateid, off, &layp, newcred, p); if (error != 0) { NFSLOCKNODE(np); np->n_flag |= NNOLAYOUT; NFSUNLOCKNODE(np); if (lckp != NULL) nfscl_lockderef(lckp); NFSFREECRED(newcred); if (layp != NULL) nfscl_rellayout(layp, 0); nfscl_relref(nmp); return (error); } } /* * Loop around finding a layout that works for the first part of * this I/O operation, and then call the function that actually * does the RPC. */ eof = 0; len = (uint64_t)uiop->uio_resid; while (len > 0 && error == 0 && eof == 0) { off = uiop->uio_offset; error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp); if (error == 0) { oresid = xfer = (uint64_t)uiop->uio_resid; if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) xfer = rflp->nfsfl_end - rflp->nfsfl_off; /* * For Flex File layout with mirrored DSs, select one * of them at random for reads. For writes and commits, * do all mirrors. */ m = NULL; tdrpc = drpc = NULL; firstmirror = 0; mirrorcnt = 1; if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 && (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) { if (rwaccess == NFSV4OPEN_ACCESSREAD) { firstmirror = arc4random() % mirrorcnt; mirrorcnt = firstmirror + 1; } else { if (docommit == 0) { /* * Save values, so uiop can be * rolled back upon a write * error. */ offs = uiop->uio_offset; resid = uiop->uio_resid; iovbase = uiop->uio_iov->iov_base; iovlen = uiop->uio_iov->iov_len; m = nfsm_uiombuflist(uiop, len, 0); if (m == NULL) { error = EFAULT; break; } } tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP, M_WAITOK | M_ZERO); } } for (i = firstmirror; i < mirrorcnt && error == 0; i++){ m2 = NULL; if (m != NULL && i < mirrorcnt - 1) m2 = m_copym(m, 0, M_COPYALL, M_WAITOK); else { m2 = m; m = NULL; } if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) { dev = rflp->nfsfl_ffm[i].dev; dip = nfscl_getdevinfo(nmp->nm_clp, dev, rflp->nfsfl_ffm[i].devp); } else { dev = rflp->nfsfl_dev; dip = nfscl_getdevinfo(nmp->nm_clp, dev, rflp->nfsfl_devp); } if (dip != NULL) { if ((rflp->nfsfl_flags & NFSFL_FLEXFILE) != 0) error = nfscl_dofflayoutio(vp, uiop, iomode, must_commit, &eof, &stateid, rwaccess, dip, layp, rflp, off, xfer, i, docommit, m2, tdrpc, newcred, p); else error = nfscl_doflayoutio(vp, uiop, iomode, must_commit, &eof, &stateid, rwaccess, dip, layp, rflp, off, xfer, docommit, newcred, p); nfscl_reldevinfo(dip); } else { if (m2 != NULL) m_freem(m2); error = EIO; } tdrpc++; } if (m != NULL) m_freem(m); tdrpc = drpc; timo = hz / 50; /* Wait for 20msec. */ if (timo < 1) timo = 1; for (i = firstmirror; i < mirrorcnt - 1 && tdrpc != NULL; i++, tdrpc++) { /* * For the unused drpc entries, both inprog and * err == 0, so this loop won't break. */ while (tdrpc->inprog != 0 && tdrpc->done == 0) tsleep(&tdrpc->tsk, PVFS, "clrpcio", timo); if (error == 0 && tdrpc->err != 0) error = tdrpc->err; if (rwaccess != NFSV4OPEN_ACCESSREAD && docommit == 0 && *must_commit == 0 && tdrpc->must_commit == 1) *must_commit = 1; } free(drpc, M_TEMP); if (error == 0) { if (mirrorcnt > 1 && rwaccess == NFSV4OPEN_ACCESSWRITE && docommit == 0) { NFSLOCKCLSTATE(); layp->nfsly_flags |= NFSLY_WRITTEN; NFSUNLOCKCLSTATE(); } lastbyte = off + xfer - 1; NFSLOCKCLSTATE(); if (lastbyte > layp->nfsly_lastbyte) layp->nfsly_lastbyte = lastbyte; NFSUNLOCKCLSTATE(); } else if (error == NFSERR_OPENMODE && rwaccess == NFSV4OPEN_ACCESSREAD) { NFSLOCKMNT(nmp); nmp->nm_state |= NFSSTA_OPENMODE; NFSUNLOCKMNT(nmp); } else if ((error == NFSERR_NOSPC || error == NFSERR_IO || error == NFSERR_NXIO) && nmp->nm_minorvers == NFSV42_MINORVERSION) { if (docommit != 0) op = NFSV4OP_COMMIT; else if (rwaccess == NFSV4OPEN_ACCESSREAD) op = NFSV4OP_READ; else op = NFSV4OP_WRITE; nfsrpc_layouterror(nmp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, off, xfer, &layp->nfsly_stateid, newcred, p, error, op, dip->nfsdi_deviceid); error = EIO; } else error = EIO; if (error == 0) len -= (oresid - (uint64_t)uiop->uio_resid); else if (mirrorcnt > 1 && rwaccess == NFSV4OPEN_ACCESSWRITE && docommit == 0) { /* * In case the rpc gets retried, roll the * uio fields changed by nfsm_uiombuflist() * back. */ uiop->uio_offset = offs; uiop->uio_resid = resid; uiop->uio_iov->iov_base = iovbase; uiop->uio_iov->iov_len = iovlen; } } } if (lckp != NULL) nfscl_lockderef(lckp); NFSFREECRED(newcred); nfscl_rellayout(layp, 0); nfscl_relref(nmp); return (error); } /* * Find a file layout that will handle the first bytes of the requested * range and return the information from it needed to the I/O operation. */ int nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess, struct nfsclflayout **retflpp) { struct nfsclflayout *flp, *nflp, *rflp; uint32_t rw; rflp = NULL; rw = rwaccess; /* For reading, do the Read list first and then the Write list. */ do { if (rw == NFSV4OPEN_ACCESSREAD) flp = LIST_FIRST(&lyp->nfsly_flayread); else flp = LIST_FIRST(&lyp->nfsly_flayrw); while (flp != NULL) { nflp = LIST_NEXT(flp, nfsfl_list); if (flp->nfsfl_off > off) break; if (flp->nfsfl_end > off && (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end)) rflp = flp; flp = nflp; } if (rw == NFSV4OPEN_ACCESSREAD) rw = NFSV4OPEN_ACCESSWRITE; else rw = 0; } while (rw != 0); if (rflp != NULL) { /* This one covers the most bytes starting at off. */ *retflpp = rflp; return (0); } return (EIO); } /* * Do I/O using an NFSv4.1 or NFSv4.2 file layout. */ static int nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p) { uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer; int commit_thru_mds, error, stripe_index, stripe_pos, minorvers; struct nfsnode *np; struct nfsfh *fhp; struct nfsclds **dspp; np = VTONFS(vp); rel_off = off - flp->nfsfl_patoff; stripe_unit_size = flp->nfsfl_util & NFSFLAYUTIL_STRIPE_MASK; stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) % dp->nfsdi_stripecnt; transfer = stripe_unit_size - (rel_off % stripe_unit_size); error = 0; /* Loop around, doing I/O for each stripe unit. */ while (len > 0 && error == 0) { stripe_index = nfsfldi_stripeindex(dp, stripe_pos); dspp = nfsfldi_addr(dp, stripe_index); if (((*dspp)->nfsclds_flags & NFSCLDS_MINORV2) != 0) minorvers = NFSV42_MINORVERSION; else minorvers = NFSV41_MINORVERSION; if (len > transfer && docommit == 0) xfer = transfer; else xfer = len; if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) { /* Dense layout. */ if (stripe_pos >= flp->nfsfl_fhcnt) return (EIO); fhp = flp->nfsfl_fh[stripe_pos]; io_off = (rel_off / (stripe_unit_size * dp->nfsdi_stripecnt)) * stripe_unit_size + rel_off % stripe_unit_size; } else { /* Sparse layout. */ if (flp->nfsfl_fhcnt > 1) { if (stripe_index >= flp->nfsfl_fhcnt) return (EIO); fhp = flp->nfsfl_fh[stripe_index]; } else if (flp->nfsfl_fhcnt == 1) fhp = flp->nfsfl_fh[0]; else fhp = np->n_fhp; io_off = off; } if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) { commit_thru_mds = 1; if (docommit != 0) error = EIO; } else { commit_thru_mds = 0; NFSLOCKNODE(np); np->n_flag |= NDSCOMMIT; NFSUNLOCKNODE(np); } if (docommit != 0) { if (error == 0) error = nfsrpc_commitds(vp, io_off, xfer, *dspp, fhp, NFS_VER4, minorvers, cred, p); if (error == 0) { /* * Set both eof and uio_resid = 0 to end any * loops. */ *eofp = 1; uiop->uio_resid = 0; } else { NFSLOCKNODE(np); np->n_flag &= ~NDSCOMMIT; NFSUNLOCKNODE(np); } } else if (rwflag == NFSV4OPEN_ACCESSREAD) error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, io_off, xfer, fhp, 0, NFS_VER4, minorvers, cred, p); else { error = nfsrpc_writeds(vp, uiop, iomode, must_commit, stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, 0, NFS_VER4, minorvers, cred, p); if (error == 0) { NFSLOCKCLSTATE(); lyp->nfsly_flags |= NFSLY_WRITTEN; NFSUNLOCKCLSTATE(); } } if (error == 0) { transfer = stripe_unit_size; stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; len -= xfer; off += xfer; } } return (error); } /* * Do I/O using an NFSv4.1 flex file layout. */ static int nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, uint64_t len, int mirror, int docommit, struct mbuf *mp, struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) { uint64_t xfer; int error; struct nfsnode *np; struct nfsfh *fhp; struct nfsclds **dspp; struct ucred *tcred; struct mbuf *m, *m2; uint32_t copylen; np = VTONFS(vp); error = 0; NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off, (uintmax_t)len); /* Loop around, doing I/O for each stripe unit. */ while (len > 0 && error == 0) { dspp = nfsfldi_addr(dp, 0); fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex]; stateidp = &flp->nfsfl_ffm[mirror].st; NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n", mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid); if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) { tcred = NFSNEWCRED(cred); tcred->cr_uid = flp->nfsfl_ffm[mirror].user; tcred->cr_gid = flp->nfsfl_ffm[mirror].group; tcred->cr_ngroups = 0; } else tcred = cred; if (rwflag == NFSV4OPEN_ACCESSREAD) copylen = dp->nfsdi_rsize; else { copylen = dp->nfsdi_wsize; if (len > copylen && mp != NULL) { /* * When a mirrored configuration needs to do * multiple writes to each mirror, all writes * except the last one must be a multiple of * 4 bytes. This is required so that the XDR * does not need padding. * If possible, clip the size to an exact * multiple of the mbuf length, so that the * split will be on an mbuf boundary. */ copylen &= 0xfffffffc; if (copylen > mp->m_len) copylen = copylen / mp->m_len * mp->m_len; } } NFSLOCKNODE(np); np->n_flag |= NDSCOMMIT; NFSUNLOCKNODE(np); if (len > copylen && docommit == 0) xfer = copylen; else xfer = len; if (docommit != 0) { if (error == 0) { /* * Do last mirrored DS commit with this thread. */ if (mirror < flp->nfsfl_mirrorcnt - 1) error = nfsio_commitds(vp, off, xfer, *dspp, fhp, dp->nfsdi_vers, dp->nfsdi_minorvers, drpc, tcred, p); else error = nfsrpc_commitds(vp, off, xfer, *dspp, fhp, dp->nfsdi_vers, dp->nfsdi_minorvers, tcred, p); NFSCL_DEBUG(4, "commitds=%d\n", error); if (error != 0 && error != EACCES && error != ESTALE) { NFSCL_DEBUG(4, "DS layreterr for commit\n"); nfscl_dserr(NFSV4OP_COMMIT, error, dp, lyp, *dspp); } } NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error); if (error == 0) { /* * Set both eof and uio_resid = 0 to end any * loops. */ *eofp = 1; uiop->uio_resid = 0; } else { NFSLOCKNODE(np); np->n_flag &= ~NDSCOMMIT; NFSUNLOCKNODE(np); } } else if (rwflag == NFSV4OPEN_ACCESSREAD) { error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, off, xfer, fhp, 1, dp->nfsdi_vers, dp->nfsdi_minorvers, tcred, p); NFSCL_DEBUG(4, "readds=%d\n", error); if (error != 0 && error != EACCES && error != ESTALE) { NFSCL_DEBUG(4, "DS layreterr for read\n"); nfscl_dserr(NFSV4OP_READ, error, dp, lyp, *dspp); } } else { if (flp->nfsfl_mirrorcnt == 1) { error = nfsrpc_writeds(vp, uiop, iomode, must_commit, stateidp, *dspp, off, xfer, fhp, 0, 1, dp->nfsdi_vers, dp->nfsdi_minorvers, tcred, p); if (error == 0) { NFSLOCKCLSTATE(); lyp->nfsly_flags |= NFSLY_WRITTEN; NFSUNLOCKCLSTATE(); } } else { m = mp; if (xfer < len) { /* The mbuf list must be split. */ m2 = nfsm_split(mp, xfer); if (m2 != NULL) mp = m2; else { m_freem(mp); error = EIO; } } NFSCL_DEBUG(4, "mcopy len=%jd xfer=%jd\n", (uintmax_t)len, (uintmax_t)xfer); /* * Do last write to a mirrored DS with this * thread. */ if (error == 0) { if (mirror < flp->nfsfl_mirrorcnt - 1) error = nfsio_writedsmir(vp, iomode, must_commit, stateidp, *dspp, off, xfer, fhp, m, dp->nfsdi_vers, dp->nfsdi_minorvers, drpc, tcred, p); else error = nfsrpc_writedsmir(vp, iomode, must_commit, stateidp, *dspp, off, xfer, fhp, m, dp->nfsdi_vers, dp->nfsdi_minorvers, tcred, p); } NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error); if (error != 0 && error != EACCES && error != ESTALE) { NFSCL_DEBUG(4, "DS layreterr for write\n"); nfscl_dserr(NFSV4OP_WRITE, error, dp, lyp, *dspp); } } } NFSCL_DEBUG(4, "aft read/writeds=%d\n", error); if (error == 0) { len -= xfer; off += xfer; } if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) NFSFREECRED(tcred); } NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error); return (error); } /* * The actual read RPC done to a DS. */ static int nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp, struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex, int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; int attrflag, error, retlen; struct nfsrv_descript nfsd; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsrv_descript *nd = &nfsd; struct nfssockreq *nrp; struct nfsvattr na; nd->nd_mrep = NULL; if (vers == 0 || vers == NFS_VER4) { nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); vers = NFS_VER4; NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers); if (flex != 0) nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); else nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); } else { nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh, fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READ]); NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READDS]); NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n"); } NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); txdr_hyper(io_off, tl); *(tl + 2) = txdr_unsigned(len); nrp = dsp->nfsclds_sockp; NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp); if (nrp == NULL) /* If NULL, use the MDS socket. */ nrp = &nmp->nm_sockreq; error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat, error); if (error != 0) return (error); if (vers == NFS_VER3) { error = nfscl_postop_attr(nd, &na, &attrflag); NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error); if (error != 0) goto nfsmout; } if (nd->nd_repstat != 0) { error = nd->nd_repstat; goto nfsmout; } if (vers == NFS_VER3) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); *eofp = fxdr_unsigned(int, *(tl + 1)); } else { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); *eofp = fxdr_unsigned(int, *tl); } NFSM_STRSIZ(retlen, len); NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp); error = nfsm_mbufuio(nd, uiop, retlen); nfsmout: if (nd->nd_mrep != NULL) m_freem(nd->nd_mrep); return (error); } /* * The actual write RPC done to a DS. */ static int nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsmount *nmp = VFSTONFS(vp->v_mount); int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC; int32_t backup; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; struct nfssockreq *nrp; struct nfsvattr na; KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); nd->nd_mrep = NULL; if (vers == 0 || vers == NFS_VER4) { nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers); vers = NFS_VER4; if (flex != 0) nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); else nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); } else { nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n"); NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); } txdr_hyper(io_off, tl); tl += 2; if (vers == NFS_VER3) *tl++ = txdr_unsigned(len); *tl++ = txdr_unsigned(*iomode); *tl = txdr_unsigned(len); error = nfsm_uiombuf(nd, uiop, len); if (error != 0) { m_freem(nd->nd_mreq); return (error); } nrp = dsp->nfsclds_sockp; if (nrp == NULL) /* If NULL, use the MDS socket. */ nrp = &nmp->nm_sockreq; error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error, nd->nd_repstat); if (error != 0) return (error); if (nd->nd_repstat != 0) { /* * In case the rpc gets retried, roll * the uio fields changed by nfsm_uiombuf() * back. */ uiop->uio_offset -= len; uiop->uio_resid += len; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - len; uiop->uio_iov->iov_len += len; error = nd->nd_repstat; } else { if (vers == NFS_VER3) { error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, NULL); NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error); if (error != 0) goto nfsmout; } NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); rlen = fxdr_unsigned(int, *tl++); NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen); if (rlen == 0) { error = NFSERR_IO; goto nfsmout; } else if (rlen < len) { backup = len - rlen; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - backup; uiop->uio_iov->iov_len += backup; uiop->uio_offset -= backup; uiop->uio_resid += backup; len = rlen; } commit = fxdr_unsigned(int, *tl++); /* * Return the lowest commitment level * obtained by any of the RPCs. */ if (committed == NFSWRITE_FILESYNC) committed = commit; else if (committed == NFSWRITE_DATASYNC && commit == NFSWRITE_UNSTABLE) committed = commit; if (commit_thru_mds != 0) { NFSLOCKMNT(nmp); if (!NFSHASWRITEVERF(nmp)) { NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); NFSSETWRITEVERF(nmp); } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF) && *must_commit != 2) { *must_commit = 1; NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); } NFSUNLOCKMNT(nmp); } else { NFSLOCKDS(dsp); if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) && *must_commit != 2) { *must_commit = 1; NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); } NFSUNLOCKDS(dsp); } } nfsmout: if (nd->nd_mrep != NULL) m_freem(nd->nd_mrep); *iomode = committed; if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; return (error); } /* * The actual write RPC done to a DS. * This variant is called from a separate kernel process for mirrors. * Any short write is considered an IO error. */ static int nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit, nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsmount *nmp = VFSTONFS(vp->v_mount); int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; struct nfssockreq *nrp; struct nfsvattr na; nd->nd_mrep = NULL; if (vers == 0 || vers == NFS_VER4) { nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); vers = NFS_VER4; NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n", minorvers); nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); } else { nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n"); NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); } txdr_hyper(io_off, tl); tl += 2; if (vers == NFS_VER3) *tl++ = txdr_unsigned(len); *tl++ = txdr_unsigned(*iomode); *tl = txdr_unsigned(len); if (len > 0) { /* Put data in mbuf chain. */ nd->nd_mb->m_next = m; } nrp = dsp->nfsclds_sockp; if (nrp == NULL) /* If NULL, use the MDS socket. */ nrp = &nmp->nm_sockreq; error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error, nd->nd_repstat); if (error != 0) return (error); if (nd->nd_repstat != 0) error = nd->nd_repstat; else { if (vers == NFS_VER3) { error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, NULL); NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n", error); if (error != 0) goto nfsmout; } NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); rlen = fxdr_unsigned(int, *tl++); NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len, rlen); if (rlen != len) { error = NFSERR_IO; NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len, rlen); goto nfsmout; } commit = fxdr_unsigned(int, *tl++); /* * Return the lowest commitment level * obtained by any of the RPCs. */ if (committed == NFSWRITE_FILESYNC) committed = commit; else if (committed == NFSWRITE_DATASYNC && commit == NFSWRITE_UNSTABLE) committed = commit; NFSLOCKDS(dsp); if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) && *must_commit != 2) { *must_commit = 1; NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); } NFSUNLOCKDS(dsp); } nfsmout: if (nd->nd_mrep != NULL) m_freem(nd->nd_mrep); *iomode = committed; if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; return (error); } /* * Start up the thread that will execute nfsrpc_writedsmir(). */ static void start_writedsmir(void *arg, int pending) { struct nfsclwritedsdorpc *drpc; drpc = (struct nfsclwritedsdorpc *)arg; drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode, &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len, drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred, drpc->p); drpc->done = 1; crfree(drpc->cred); NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err); } /* * Set up the write DS mirror call for the pNFS I/O thread. */ static int nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit, nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len, struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) { int error, ret; error = 0; drpc->done = 0; drpc->vp = vp; drpc->iomode = *iomode; drpc->must_commit = *must_commit; drpc->stateidp = stateidp; drpc->dsp = dsp; drpc->off = off; drpc->len = len; drpc->fhp = fhp; drpc->m = m; drpc->vers = vers; drpc->minorvers = minorvers; drpc->cred = crhold(cred); drpc->p = p; drpc->inprog = 0; ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_writedsmir, drpc); NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret); } if (ret != 0) { error = nfsrpc_writedsmir(vp, iomode, &drpc->must_commit, stateidp, dsp, off, len, fhp, m, vers, minorvers, cred, p); crfree(drpc->cred); } NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error); return (error); } /* * Free up the nfsclds structure. */ void nfscl_freenfsclds(struct nfsclds *dsp) { int i; if (dsp == NULL) return; if (dsp->nfsclds_sockp != NULL) { NFSFREECRED(dsp->nfsclds_sockp->nr_cred); NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx); free(dsp->nfsclds_sockp->nr_nam, M_SONAME); free(dsp->nfsclds_sockp, M_NFSSOCKREQ); } NFSFREEMUTEX(&dsp->nfsclds_mtx); NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx); for (i = 0; i < NFSV4_CBSLOTS; i++) { if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL) m_freem( dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply); } free(dsp, M_NFSCLDS); } static enum nfsclds_state nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp, struct nfsclds **retdspp, uint32_t *sequencep) { struct nfsclds *dsp; int fndseq; /* * Search the list of nfsclds structures for one with the same * server. */ fndseq = 0; TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && dsp->nfsclds_servownlen != 0 && !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, dsp->nfsclds_servownlen) && dsp->nfsclds_sess.nfsess_defunct == 0) { NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", TAILQ_FIRST(&nmp->nm_sess), dsp, dsp->nfsclds_flags); if (fndseq == 0) { /* Get sequenceid# from first entry. */ *sequencep = dsp->nfsclds_sess.nfsess_sequenceid; fndseq = 1; } /* Server major id matches. */ if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) { *retdspp = dsp; return (NFSDSP_USETHISSESSION); } } } if (fndseq != 0) return (NFSDSP_SEQTHISSESSION); return (NFSDSP_NOTFOUND); } /* * NFS commit rpc to a NFSv4.1 DS. */ static int nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfssockreq *nrp; struct nfsvattr na; int attrflag, error; nd->nd_mrep = NULL; if (vers == 0 || vers == NFS_VER4) { nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); vers = NFS_VER4; } else { nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh, fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMIT]); NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMITDS]); } NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers, minorvers); NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); txdr_hyper(offset, tl); tl += 2; *tl = txdr_unsigned(cnt); nrp = dsp->nfsclds_sockp; if (nrp == NULL) /* If NULL, use the MDS socket. */ nrp = &nmp->nm_sockreq; error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error, nd->nd_repstat); if (error != 0) return (error); if (nd->nd_repstat == 0) { if (vers == NFS_VER3) { error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, NULL); NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error); if (error != 0) goto nfsmout; } NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); NFSLOCKDS(dsp); if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); error = NFSERR_STALEWRITEVERF; } NFSUNLOCKDS(dsp); } nfsmout: if (error == 0 && nd->nd_repstat != 0) error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * Start up the thread that will execute nfsrpc_commitds(). */ static void start_commitds(void *arg, int pending) { struct nfsclwritedsdorpc *drpc; drpc = (struct nfsclwritedsdorpc *)arg; drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred, drpc->p); drpc->done = 1; crfree(drpc->cred); NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err); } /* * Set up the commit DS mirror call for the pNFS I/O thread. */ static int nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) { int error, ret; error = 0; drpc->done = 0; drpc->vp = vp; drpc->off = offset; drpc->len = cnt; drpc->dsp = dsp; drpc->fhp = fhp; drpc->vers = vers; drpc->minorvers = minorvers; drpc->cred = crhold(cred); drpc->p = p; drpc->inprog = 0; ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_commitds, drpc); NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret); } if (ret != 0) { error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers, minorvers, cred, p); crfree(drpc->cred); } NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error); return (error); } /* * NFS Advise rpc */ int nfsrpc_advise(vnode_t vp, off_t offset, uint64_t cnt, int advise, struct ucred *cred, NFSPROC_T *p) { u_int32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; nfsattrbit_t hints; int error; NFSZERO_ATTRBIT(&hints); if (advise == POSIX_FADV_WILLNEED) NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); else if (advise == POSIX_FADV_DONTNEED) NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); else return (0); NFSCL_REQSTART(nd, NFSPROC_IOADVISE, vp, cred); nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER); txdr_hyper(offset, tl); tl += 2; txdr_hyper(cnt, tl); nfsrv_putattrbit(nd, &hints); error = nfscl_request(nd, vp, p, cred); if (error != 0) return (error); if (nd->nd_repstat != 0) error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } #ifdef notyet /* * NFS advise rpc to a NFSv4.2 DS. */ static int nfsrpc_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfssockreq *nrp; nfsattrbit_t hints; int error; /* For NFS DSs prior to NFSv4.2, just return OK. */ if (vers == NFS_VER3 || minorversion < NFSV42_MINORVERSION) return (0); NFSZERO_ATTRBIT(&hints); if (advise == POSIX_FADV_WILLNEED) NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); else if (advise == POSIX_FADV_DONTNEED) NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); else return (0); nd->nd_mrep = NULL; nfscl_reqstart(nd, NFSPROC_IOADVISEDS, nmp, fhp->nfh_fh, fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); vers = NFS_VER4; NFSCL_DEBUG(4, "nfsrpc_adviseds: vers=%d minvers=%d\n", vers, minorvers); nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); txdr_hyper(offset, tl); tl += 2; *tl = txdr_unsigned(cnt); nfsrv_putattrbit(nd, &hints); nrp = dsp->nfsclds_sockp; if (nrp == NULL) /* If NULL, use the MDS socket. */ nrp = &nmp->nm_sockreq; error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); NFSCL_DEBUG(4, "nfsrpc_adviseds: err=%d stat=%d\n", error, nd->nd_repstat); if (error != 0) return (error); if (nd->nd_repstat != 0) error = nd->nd_repstat; m_freem(nd->nd_mrep); return (error); } /* * Start up the thread that will execute nfsrpc_commitds(). */ static void start_adviseds(void *arg, int pending) { struct nfsclwritedsdorpc *drpc; drpc = (struct nfsclwritedsdorpc *)arg; drpc->err = nfsrpc_adviseds(drpc->vp, drpc->off, drpc->len, drpc->advise, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred, drpc->p); drpc->done = 1; crfree(drpc->cred); NFSCL_DEBUG(4, "start_adviseds: err=%d\n", drpc->err); } /* * Set up the advise DS mirror call for the pNFS I/O thread. */ static int nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) { int error, ret; error = 0; drpc->done = 0; drpc->vp = vp; drpc->off = offset; drpc->len = cnt; drpc->advise = advise; drpc->dsp = dsp; drpc->fhp = fhp; drpc->vers = vers; drpc->minorvers = minorvers; drpc->cred = crhold(cred); drpc->p = p; drpc->inprog = 0; ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_adviseds, drpc); NFSCL_DEBUG(4, "nfsio_adviseds: nfs_pnfsio=%d\n", ret); } if (ret != 0) { error = nfsrpc_adviseds(vp, offset, cnt, advise, dsp, fhp, vers, minorvers, cred, p); crfree(drpc->cred); } NFSCL_DEBUG(4, "nfsio_adviseds: error=%d\n", error); return (error); } #endif /* notyet */ /* * Do the Allocate operation, retrying for recovery. */ int nfsrpc_allocate(vnode_t vp, off_t off, off_t len, struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) { int error, expireret = 0, retrycnt, nostateid; uint32_t clidrev = 0; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsfh *nfhp = NULL; nfsv4stateid_t stateid; off_t tmp_off; void *lckp; if (len < 0) return (EINVAL); if (len == 0) return (0); tmp_off = off + len; NFSLOCKMNT(nmp); if (tmp_off > nmp->nm_maxfilesize || tmp_off < off) { NFSUNLOCKMNT(nmp); return (EFBIG); } if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; NFSUNLOCKMNT(nmp); nfhp = VTONFS(vp)->n_fhp; retrycnt = 0; do { lckp = NULL; nostateid = 0; nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp); if (stateid.other[0] == 0 && stateid.other[1] == 0 && stateid.other[2] == 0) { nostateid = 1; NFSCL_DEBUG(1, "stateid0 in allocate\n"); } /* * Not finding a stateid should probably never happen, * but just return an error for this case. */ if (nostateid != 0) error = EIO; else error = nfsrpc_allocaterpc(vp, off, len, &stateid, nap, attrflagp, cred, p); if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) nfscl_lockderef(lckp); 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_allocate"); } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && error == NFSERR_BADSTATEID)) && clidrev != 0) { expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); } 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 = EIO; return (error); } /* * The allocate RPC. */ static int nfsrpc_allocaterpc(vnode_t vp, off_t off, off_t len, nfsv4stateid_t *stateidp, struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; int error; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; nfsattrbit_t attrbits; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_ALLOCATE, vp, cred); nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); txdr_hyper(off, tl); tl += 2; txdr_hyper(len, tl); tl += 2; *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, p, cred); if (error != 0) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); error = nfsm_loadattr(nd, nap); if (error == 0) *attrflagp = NFS_LATTR_NOSHRINK; } else error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * Set up the XDR arguments for the LayoutGet operation. */ static void nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype, int layoutlen, int usecurstateid) { uint32_t *tl; NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + NFSX_STATEID); *tl++ = newnfs_false; /* Don't signal availability. */ *tl++ = txdr_unsigned(layouttype); *tl++ = txdr_unsigned(iomode); txdr_hyper(offset, tl); tl += 2; txdr_hyper(len, tl); tl += 2; txdr_hyper(minlen, tl); tl += 2; if (usecurstateid != 0) { /* Special stateid for Current stateid. */ *tl++ = txdr_unsigned(1); *tl++ = 0; *tl++ = 0; *tl++ = 0; } else { *tl++ = txdr_unsigned(stateidp->seqid); NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); *tl++ = stateidp->other[0]; *tl++ = stateidp->other[1]; *tl++ = stateidp->other[2]; } *tl = txdr_unsigned(layoutlen); } /* * Parse the reply for a successful LayoutGet operation. */ static int nfsrv_parselayoutget(struct nfsmount *nmp, struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp) { uint32_t *tl; struct nfsclflayout *flp, *prevflp, *tflp; int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen; int m, mirrorcnt; uint64_t retlen, off; struct nfsfh *nfhp; uint8_t *cp; uid_t user; gid_t grp; NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n"); error = 0; flp = NULL; gotiomode = -1; NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); if (*tl++ != 0) *retonclosep = 1; else *retonclosep = 0; stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, (int)stateidp->seqid); stateidp->other[0] = *tl++; stateidp->other[1] = *tl++; stateidp->other[2] = *tl++; cnt = fxdr_unsigned(int, *tl); NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); if (cnt <= 0 || cnt > 10000) { /* Don't accept more than 10000 layouts in reply. */ error = NFSERR_BADXDR; goto nfsmout; } for (i = 0; i < cnt; i++) { /* Dissect to the layout type. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); off = fxdr_hyper(tl); tl += 2; retlen = fxdr_hyper(tl); tl += 2; iomode = fxdr_unsigned(int, *tl++); laytype = fxdr_unsigned(int, *tl); NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype, (uintmax_t)off, (uintmax_t)retlen, iomode); /* Ignore length of layout body for now. */ if (laytype == NFSLAYOUT_NFSV4_1_FILES) { /* Parse the File layout up to fhcnt. */ NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER + NFSX_V4DEVICEID); fhcnt = fxdr_unsigned(int, *(tl + 4 + NFSX_V4DEVICEID / NFSX_UNSIGNED)); NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); if (fhcnt < 0 || fhcnt > 100) { /* Don't accept more than 100 file handles. */ error = NFSERR_BADXDR; goto nfsmout; } if (fhcnt > 0) flp = malloc(sizeof(*flp) + fhcnt * sizeof(struct nfsfh *), M_NFSFLAYOUT, M_WAITOK); else flp = malloc(sizeof(*flp), M_NFSFLAYOUT, M_WAITOK); flp->nfsfl_flags = NFSFL_FILE; flp->nfsfl_fhcnt = 0; flp->nfsfl_devp = NULL; flp->nfsfl_off = off; if (flp->nfsfl_off + retlen < flp->nfsfl_off) flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; else flp->nfsfl_end = flp->nfsfl_off + retlen; flp->nfsfl_iomode = iomode; if (gotiomode == -1) gotiomode = flp->nfsfl_iomode; /* Ignore layout body length for now. */ NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID); tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); mtx_lock(&nmp->nm_mtx); if (nmp->nm_minorvers > 1 && (flp->nfsfl_util & NFSFLAYUTIL_IOADVISE_THRU_MDS) != 0) nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; mtx_unlock(&nmp->nm_mtx); flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n", flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff); for (j = 0; j < fhcnt; j++) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); nfhlen = fxdr_unsigned(int, *tl); if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { error = NFSERR_BADXDR; goto nfsmout; } nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, M_NFSFH, M_WAITOK); flp->nfsfl_fh[j] = nfhp; flp->nfsfl_fhcnt++; nfhp->nfh_len = nfhlen; NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); } } else if (laytype == NFSLAYOUT_FLEXFILE) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); mirrorcnt = fxdr_unsigned(int, *(tl + 2)); NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt); if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) { error = NFSERR_BADXDR; goto nfsmout; } flp = malloc(sizeof(*flp) + mirrorcnt * sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK); flp->nfsfl_flags = NFSFL_FLEXFILE; flp->nfsfl_mirrorcnt = mirrorcnt; for (j = 0; j < mirrorcnt; j++) flp->nfsfl_ffm[j].devp = NULL; flp->nfsfl_off = off; if (flp->nfsfl_off + retlen < flp->nfsfl_off) flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; else flp->nfsfl_end = flp->nfsfl_off + retlen; flp->nfsfl_iomode = iomode; if (gotiomode == -1) gotiomode = flp->nfsfl_iomode; flp->nfsfl_stripeunit = fxdr_hyper(tl); NFSCL_DEBUG(4, "stripeunit=%ju\n", (uintmax_t)flp->nfsfl_stripeunit); for (j = 0; j < mirrorcnt; j++) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); k = fxdr_unsigned(int, *tl); if (k < 1 || k > 128) { error = NFSERR_BADXDR; goto nfsmout; } NFSCL_DEBUG(4, "servercnt=%d\n", k); for (l = 0; l < k; l++) { NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + NFSX_STATEID + 2 * NFSX_UNSIGNED); if (l == 0) { /* Just use the first server. */ NFSBCOPY(tl, flp->nfsfl_ffm[j].dev, NFSX_V4DEVICEID); tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); tl++; flp->nfsfl_ffm[j].st.seqid = *tl++; flp->nfsfl_ffm[j].st.other[0] = *tl++; flp->nfsfl_ffm[j].st.other[1] = *tl++; flp->nfsfl_ffm[j].st.other[2] = *tl++; NFSCL_DEBUG(4, "st.seqid=%u " "st.o0=0x%x st.o1=0x%x " "st.o2=0x%x\n", flp->nfsfl_ffm[j].st.seqid, flp->nfsfl_ffm[j].st.other[0], flp->nfsfl_ffm[j].st.other[1], flp->nfsfl_ffm[j].st.other[2]); } else tl += ((NFSX_V4DEVICEID + NFSX_STATEID + NFSX_UNSIGNED) / NFSX_UNSIGNED); fhcnt = fxdr_unsigned(int, *tl); NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); if (fhcnt < 1 || fhcnt > NFSDEV_MAXVERS) { error = NFSERR_BADXDR; goto nfsmout; } for (m = 0; m < fhcnt; m++) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); nfhlen = fxdr_unsigned(int, *tl); NFSCL_DEBUG(4, "nfhlen=%d\n", nfhlen); if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { error = NFSERR_BADXDR; goto nfsmout; } NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); if (l == 0) { flp->nfsfl_ffm[j].fhcnt = fhcnt; nfhp = malloc( sizeof(*nfhp) + nfhlen - 1, M_NFSFH, M_WAITOK); flp->nfsfl_ffm[j].fh[m] = nfhp; nfhp->nfh_len = nfhlen; NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); NFSCL_DEBUG(4, "got fh\n"); } } /* Now, get the ffsd_user/ffds_group. */ error = nfsrv_parseug(nd, 0, &user, &grp, curthread); NFSCL_DEBUG(4, "after parseu=%d\n", error); if (error == 0) error = nfsrv_parseug(nd, 1, &user, &grp, curthread); NFSCL_DEBUG(4, "aft parseg=%d\n", grp); if (error != 0) goto nfsmout; NFSCL_DEBUG(4, "user=%d group=%d\n", user, grp); if (l == 0) { flp->nfsfl_ffm[j].user = user; flp->nfsfl_ffm[j].group = grp; NFSCL_DEBUG(4, "usr=%d grp=%d\n", user, grp); } } } NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++); #ifdef notnow /* * At this time, there is no flag. * NFSFLEXFLAG_IOADVISE_THRU_MDS might need to be * added, or it may never exist? */ mtx_lock(&nmp->nm_mtx); if (nmp->nm_minorvers > 1 && (flp->nfsfl_fflags & NFSFLEXFLAG_IOADVISE_THRU_MDS) != 0) nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; mtx_unlock(&nmp->nm_mtx); #endif flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl); NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n", flp->nfsfl_fflags, flp->nfsfl_statshint); } else { error = NFSERR_BADXDR; goto nfsmout; } if (flp->nfsfl_iomode == gotiomode) { /* Keep the list in increasing offset order. */ tflp = LIST_FIRST(flhp); prevflp = NULL; while (tflp != NULL && tflp->nfsfl_off < flp->nfsfl_off) { prevflp = tflp; tflp = LIST_NEXT(tflp, nfsfl_list); } if (prevflp == NULL) LIST_INSERT_HEAD(flhp, flp, nfsfl_list); else LIST_INSERT_AFTER(prevflp, flp, nfsfl_list); NFSCL_DEBUG(4, "flp inserted\n"); } else { printf("nfscl_layoutget(): got wrong iomode\n"); nfscl_freeflayout(flp); } flp = NULL; } nfsmout: NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error); if (error != 0 && flp != NULL) nfscl_freeflayout(flp); return (error); } /* * Parse a user/group digit string. */ static int nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp, NFSPROC_T *p) { uint32_t *tl; char *cp, *str, str0[NFSV4_SMALLSTR + 1]; uint32_t len = 0; int error = 0; NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(uint32_t, *tl); str = NULL; if (len > NFSV4_OPAQUELIMIT) { error = NFSERR_BADXDR; goto nfsmout; } NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len); if (len == 0) { if (dogrp != 0) *gidp = GID_NOGROUP; else *uidp = UID_NOBODY; return (0); } if (len > NFSV4_SMALLSTR) str = malloc(len + 1, M_TEMP, M_WAITOK); else str = str0; NFSM_DISSECT(cp, char *, NFSM_RNDUP(len)); NFSBCOPY(cp, str, len); str[len] = '\0'; NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str); if (dogrp != 0) error = nfsv4_strtogid(nd, str, len, gidp); else error = nfsv4_strtouid(nd, str, len, uidp); nfsmout: if (len > NFSV4_SMALLSTR) free(str, M_TEMP); NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error); return (error); } /* * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), * so that it does both an Open and a Layoutget. */ static int nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, struct ucred *cred, NFSPROC_T *p) { struct nfscllayout *lyp; struct nfsclflayout *flp; struct nfsclflayouthead flh; int error, islocked, layoutlen, recalled, retonclose, usecurstateid; int layouttype, laystat; nfsv4stateid_t stateid; struct nfsclsession *tsep; error = 0; if (NFSHASFLEXFILE(nmp)) layouttype = NFSLAYOUT_FLEXFILE; else layouttype = NFSLAYOUT_NFSV4_1_FILES; /* * If lyp is returned non-NULL, there will be a refcnt (shared lock) * on it, iff flp != NULL or a lock (exclusive lock) on it iff * flp == NULL. */ lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, mode, &flp, &recalled); NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); if (lyp == NULL) islocked = 0; else if (flp != NULL) islocked = 1; else islocked = 2; if ((lyp == NULL || flp == NULL) && recalled == 0) { LIST_INIT(&flh); tsep = nfsmnt_mdssession(nmp); layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); if (lyp == NULL) usecurstateid = 1; else { usecurstateid = 0; stateid.seqid = lyp->nfsly_stateid.seqid; stateid.other[0] = lyp->nfsly_stateid.other[0]; stateid.other[1] = lyp->nfsly_stateid.other[1]; stateid.other[2] = lyp->nfsly_stateid.other[2]; } error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, mode, op, name, namelen, dpp, &stateid, usecurstateid, layouttype, layoutlen, &retonclose, &flh, &laystat, cred, p); NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", laystat, error); laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat, &islocked, cred, p); } else error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); if (islocked == 2) nfscl_rellayout(lyp, 1); else if (islocked == 1) nfscl_rellayout(lyp, 0); return (error); } /* * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are * handled by nfsrpc_openrpc(). * For the case where op == NULL, dvp is the directory. When op != NULL, it * can be NULL. */ static int nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, nfsv4stateid_t *stateidp, int usecurstateid, int layouttype, int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, int *laystatp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfscldeleg *ndp = NULL; struct nfsvattr nfsva; struct nfsclsession *tsep; uint32_t rflags, deleg; nfsattrbit_t attrbits; int error, ret, acesize, limitby, iomode; *dpp = NULL; *laystatp = ENXIO; nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); *tl++ = txdr_unsigned(mode & (NFSV4OPEN_ACCESSBOTH | NFSV4OPEN_WANTDELEGMASK)); *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; *tl = tsep->nfsess_clientid.lval[1]; nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); if (NFSHASNFSV4N(nmp)) { *tl = txdr_unsigned(NFSV4OPEN_CLAIMFH); } else { *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); nfsm_strtom(nd, name, namelen); } NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) iomode = NFSLAYOUTIOMODE_RW; else iomode = NFSLAYOUTIOMODE_READ; nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, layouttype, layoutlen, usecurstateid); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); if (nd->nd_repstat != 0) *laystatp = nd->nd_repstat; if ((nd->nd_flag & ND_NOMOREDATA) == 0) { /* ND_NOMOREDATA will be set if the Open operation failed. */ NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); op->nfso_stateid.seqid = *tl++; op->nfso_stateid.other[0] = *tl++; op->nfso_stateid.other[1] = *tl++; op->nfso_stateid.other[2] = *tl; rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error != 0) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(u_int32_t, *tl); if (deleg == NFSV4OPEN_DELEGATEREAD || deleg == NFSV4OPEN_DELEGATEWRITE) { if (!(op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_FIRSTDELEG)) op->nfso_own->nfsow_clp->nfsc_flags |= (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, M_NFSCLDELEG, M_WAITOK); LIST_INIT(&ndp->nfsdl_owner); LIST_INIT(&ndp->nfsdl_lock); ndp->nfsdl_clp = op->nfso_own->nfsow_clp; ndp->nfsdl_fhlen = newfhlen; NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); newnfs_copyincred(cred, &ndp->nfsdl_cred); nfscl_lockinit(&ndp->nfsdl_rwlock); NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); ndp->nfsdl_stateid.seqid = *tl++; ndp->nfsdl_stateid.other[0] = *tl++; ndp->nfsdl_stateid.other[1] = *tl++; ndp->nfsdl_stateid.other[2] = *tl++; ret = fxdr_unsigned(int, *tl); if (deleg == NFSV4OPEN_DELEGATEWRITE) { ndp->nfsdl_flags = NFSCLDL_WRITE; /* * Indicates how much the file can grow. */ NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); limitby = fxdr_unsigned(int, *tl++); switch (limitby) { case NFSV4OPEN_LIMITSIZE: ndp->nfsdl_sizelimit = fxdr_hyper(tl); break; case NFSV4OPEN_LIMITBLOCKS: ndp->nfsdl_sizelimit = fxdr_unsigned(u_int64_t, *tl++); ndp->nfsdl_sizelimit *= fxdr_unsigned(u_int64_t, *tl); break; default: error = NFSERR_BADXDR; goto nfsmout; }; } else ndp->nfsdl_flags = NFSCLDL_READ; if (ret != 0) ndp->nfsdl_flags |= NFSCLDL_RECALL; error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false, &ret, &acesize, p); if (error != 0) goto nfsmout; } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && NFSHASNFSV4N(nmp)) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(uint32_t, *tl); if (deleg == NFSV4OPEN_CONTENTION || deleg == NFSV4OPEN_RESOURCE) NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; } if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || nfscl_assumeposixlocks) op->nfso_posixlock = 1; else op->nfso_posixlock = 0; NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); /* If the 2nd element == NFS_OK, the Getattr succeeded. */ if (*++tl == 0) { error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, p, cred); if (error != 0) goto nfsmout; if (ndp != NULL) { ndp->nfsdl_change = nfsva.na_filerev; ndp->nfsdl_modtime = nfsva.na_mtime; ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; *dpp = ndp; ndp = NULL; } /* * At this point, the Open has succeeded, so set * nd_repstat = NFS_OK. If the Layoutget failed, * this function just won't return a layout. */ if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); *laystatp = fxdr_unsigned(int, *++tl); if (*laystatp == 0) { error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep, flhp); if (error != 0) *laystatp = error; } } else nd->nd_repstat = 0; /* Return 0 for Open. */ } } if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; nfsmout: free(ndp, M_NFSCLDELEG); m_freem(nd->nd_mrep); return (error); } /* * Similar nfsrpc_createv4(), but also does the LayoutGet operation. * Used only for mounts with pNFS enabled. */ static int nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, int *unlockedp, nfsv4stateid_t *stateidp, int usecurstateid, int layouttype, int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, int *laystatp) { uint32_t *tl; int error = 0, deleg, newone, ret, acesize, limitby; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsclopen *op; struct nfscldeleg *dp = NULL; struct nfsnode *np; struct nfsfh *nfhp; struct nfsclsession *tsep; nfsattrbit_t attrbits; nfsv4stateid_t stateid; struct nfsmount *nmp; nmp = VFSTONFS(dvp->v_mount); np = VTONFS(dvp); *laystatp = ENXIO; *unlockedp = 0; *nfhpp = NULL; *dpp = NULL; *attrflagp = 0; *dattrflagp = 0; if (namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp, cred); /* * For V4, this is actually an Open op. */ NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(owp->nfsow_seqid); if (NFSHASNFSV4N(nmp)) { if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 && nfs_numnfscbd > 0) *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTWRITEDELEG); else *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTNODELEG); } else *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD); *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; *tl = tsep->nfsess_clientid.lval[1]; nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); if ((fmode & O_EXCL) != 0) { if (NFSHASSESSPERSIST(nmp)) { /* Use GUARDED for persistent sessions. */ *tl = txdr_unsigned(NFSCREATE_GUARDED); nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } else { /* Otherwise, use EXCLUSIVE4_1. */ *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); *tl++ = cverf.lval[0]; *tl = cverf.lval[1]; nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } } else { *tl = txdr_unsigned(NFSCREATE_UNCHECKED); nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); nfsm_strtom(nd, name, namelen); /* Get the new file's handle and attributes, plus save the FH. */ NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_SAVEFH); *tl++ = txdr_unsigned(NFSV4OP_GETFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); nfsrv_putattrbit(nd, &attrbits); /* Get the directory's post-op attributes. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, layouttype, layoutlen, usecurstateid); error = nfscl_request(nd, dvp, p, cred); if (error != 0) return (error); NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, error); if (nd->nd_repstat != 0) *laystatp = nd->nd_repstat; NFSCL_INCRSEQID(owp->nfsow_seqid, nd); if ((nd->nd_flag & ND_NOMOREDATA) == 0) { NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); stateid.seqid = *tl++; stateid.other[0] = *tl++; stateid.other[1] = *tl++; stateid.other[2] = *tl; error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error != 0) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(int, *tl); if (deleg == NFSV4OPEN_DELEGATEREAD || deleg == NFSV4OPEN_DELEGATEWRITE) { if (!(owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_FIRSTDELEG)) owp->nfsow_clp->nfsc_flags |= (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, M_NFSCLDELEG, M_WAITOK); LIST_INIT(&dp->nfsdl_owner); LIST_INIT(&dp->nfsdl_lock); dp->nfsdl_clp = owp->nfsow_clp; newnfs_copyincred(cred, &dp->nfsdl_cred); nfscl_lockinit(&dp->nfsdl_rwlock); NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); dp->nfsdl_stateid.seqid = *tl++; dp->nfsdl_stateid.other[0] = *tl++; dp->nfsdl_stateid.other[1] = *tl++; dp->nfsdl_stateid.other[2] = *tl++; ret = fxdr_unsigned(int, *tl); if (deleg == NFSV4OPEN_DELEGATEWRITE) { dp->nfsdl_flags = NFSCLDL_WRITE; /* * Indicates how much the file can grow. */ NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); limitby = fxdr_unsigned(int, *tl++); switch (limitby) { case NFSV4OPEN_LIMITSIZE: dp->nfsdl_sizelimit = fxdr_hyper(tl); break; case NFSV4OPEN_LIMITBLOCKS: dp->nfsdl_sizelimit = fxdr_unsigned(u_int64_t, *tl++); dp->nfsdl_sizelimit *= fxdr_unsigned(u_int64_t, *tl); break; default: error = NFSERR_BADXDR; goto nfsmout; }; } else { dp->nfsdl_flags = NFSCLDL_READ; } if (ret != 0) dp->nfsdl_flags |= NFSCLDL_RECALL; error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false, &ret, &acesize, p); if (error != 0) goto nfsmout; } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && NFSHASNFSV4N(nmp)) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); deleg = fxdr_unsigned(uint32_t, *tl); if (deleg == NFSV4OPEN_CONTENTION || deleg == NFSV4OPEN_RESOURCE) NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; } /* Now, we should have the status for the SaveFH. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*++tl == 0) { NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); /* * Now, process the GetFH and Getattr for the newly * created file. nfscl_mtofh() will set * ND_NOMOREDATA if these weren't successful. */ error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); if (error != 0) goto nfsmout; } else nd->nd_flag |= ND_NOMOREDATA; /* Now we have the PutFH and Getattr for the directory. */ if ((nd->nd_flag & ND_NOMOREDATA) == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*++tl != 0) nd->nd_flag |= ND_NOMOREDATA; else { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*++tl != 0) nd->nd_flag |= ND_NOMOREDATA; } } if ((nd->nd_flag & ND_NOMOREDATA) == 0) { /* Load the directory attributes. */ error = nfsm_loadattr(nd, dnap); NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); if (error != 0) goto nfsmout; *dattrflagp = 1; if (dp != NULL && *attrflagp != 0) { dp->nfsdl_change = nnap->na_filerev; dp->nfsdl_modtime = nnap->na_mtime; dp->nfsdl_flags |= NFSCLDL_MODTIMESET; } /* * We can now complete the Open state. */ nfhp = *nfhpp; if (dp != NULL) { dp->nfsdl_fhlen = nfhp->nfh_len; NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); } /* * Get an Open structure that will be * attached to the OpenOwner, acquired already. */ error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, cred, p, NULL, &op, &newone, NULL, 0, false); if (error != 0) goto nfsmout; op->nfso_stateid = stateid; newnfs_copyincred(cred, &op->nfso_cred); nfscl_openrelease(nmp, op, error, newone); *unlockedp = 1; /* Now, handle the RestoreFH and LayoutGet. */ if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); *laystatp = fxdr_unsigned(int, *(tl + 3)); if (*laystatp == 0) { error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep, flhp); if (error != 0) *laystatp = error; } NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n", error); } else nd->nd_repstat = 0; } } if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; if (error == NFSERR_STALECLIENTID) nfscl_initiate_recovery(owp->nfsow_clp); nfsmout: NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error); if (error == 0) *dpp = dp; else free(dp, M_NFSCLDELEG); m_freem(nd->nd_mrep); return (error); } /* * Similar to nfsrpc_getopenlayout(), except that it used for the Create case. */ static int nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, int *unlockedp) { struct nfscllayout *lyp; struct nfsclflayouthead flh; struct nfsfh *nfhp; struct nfsclsession *tsep; struct nfsmount *nmp; nfsv4stateid_t stateid; int error, layoutlen, layouttype, retonclose, laystat; error = 0; nmp = VFSTONFS(dvp->v_mount); if (NFSHASFLEXFILE(nmp)) layouttype = NFSLAYOUT_FLEXFILE; else layouttype = NFSLAYOUT_NFSV4_1_FILES; LIST_INIT(&flh); tsep = nfsmnt_mdssession(nmp); layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode, owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose, &flh, &laystat); NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n", laystat, error); lyp = NULL; if (laystat == 0) { nfhp = *nfhpp; laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL, cred, p); } else laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL, cred, p); if (laystat == 0) nfscl_rellayout(lyp, 0); return (error); } /* * Process the results of a layoutget() operation. */ static int nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp, int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit, struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype, int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p) { struct nfsclflayout *tflp; struct nfscldevinfo *dip; uint8_t *dev; int i, mirrorcnt; if (laystat == NFSERR_UNKNLAYOUTTYPE) { NFSLOCKMNT(nmp); if (!NFSHASFLEXFILE(nmp)) { /* Switch to using Flex File Layout. */ nmp->nm_state |= NFSSTA_FLEXFILE; } else if (layouttype == NFSLAYOUT_FLEXFILE) { /* Disable pNFS. */ NFSCL_DEBUG(1, "disable PNFS\n"); nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE); } NFSUNLOCKMNT(nmp); } if (laystat == 0) { NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n"); LIST_FOREACH(tflp, flhp, nfsfl_list) { if (layouttype == NFSLAYOUT_FLEXFILE) mirrorcnt = tflp->nfsfl_mirrorcnt; else mirrorcnt = 1; for (i = 0; i < mirrorcnt; i++) { laystat = nfscl_adddevinfo(nmp, NULL, i, tflp); NFSCL_DEBUG(4, "aft adddev=%d\n", laystat); if (laystat != 0) { if (layouttype == NFSLAYOUT_FLEXFILE) dev = tflp->nfsfl_ffm[i].dev; else dev = tflp->nfsfl_dev; laystat = nfsrpc_getdeviceinfo(nmp, dev, layouttype, notifybit, &dip, cred, p); NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n", laystat); if (laystat != 0) goto out; laystat = nfscl_adddevinfo(nmp, dip, i, tflp); if (laystat != 0) printf("nfsrpc_layoutgetresout" ": cannot add\n"); } } } } out: if (laystat == 0) { /* * nfscl_layout() always returns with the nfsly_lock * set to a refcnt (shared lock). * Passing in dvp is sufficient, since it is only used to * get the fsid for the file system. */ laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp, layouttype, retonclose, flhp, lypp, cred, p); NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n", laystat); if (laystat == 0 && islockedp != NULL) *islockedp = 1; } return (laystat); } /* * nfs copy_file_range operation. */ int nfsrpc_copy_file_range(vnode_t invp, off_t *inoffp, vnode_t outvp, off_t *outoffp, size_t *lenp, unsigned int flags, int *inattrflagp, struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap, struct ucred *cred, bool consecutive, bool *must_commitp) { int commit, error, expireret = 0, retrycnt; u_int32_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_copyrpc(invp, *inoffp, outvp, *outoffp, lenp, &instateid, &outstateid, innap, inattrflagp, outnap, outattrflagp, consecutive, &commit, cred, curthread); if (error == 0) { if (commit != NFSWRITE_FILESYNC) *must_commitp = true; *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 copy RPC. */ static int nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff, size_t *lenp, nfsv4stateid_t *instateidp, nfsv4stateid_t *outstateidp, struct nfsvattr *innap, int *inattrflagp, struct nfsvattr *outnap, int *outattrflagp, bool consecutive, int *commitp, 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; *commitp = NFSWRITE_UNSTABLE; len = *lenp; *lenp = 0; if (len > nfs_maxcopyrange) len = nfs_maxcopyrange; nfscl_reqstart(nd, NFSPROC_COPY, 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 Copy, 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 Copy. */ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_COPY); nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID); nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + 4 * NFSX_UNSIGNED); txdr_hyper(inoff, tl); tl += 2; txdr_hyper(outoff, tl); tl += 2; txdr_hyper(len, tl); tl += 2; if (consecutive) *tl++ = newnfs_true; else *tl++ = newnfs_false; *tl++ = newnfs_true; *tl++ = 0; /* 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 Copy. */ 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 *, NFSX_UNSIGNED); if (*tl != 0) { /* There should be no callback ids. */ error = NFSERR_BADXDR; goto nfsmout; } NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED + NFSX_VERF); len = fxdr_hyper(tl); tl += 2; *commitp = fxdr_unsigned(int, *tl++); NFSLOCKMNT(nmp); if (!NFSHASWRITEVERF(nmp)) { NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); NFSSETWRITEVERF(nmp); } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); nd->nd_repstat = NFSERR_STALEWRITEVERF; } NFSUNLOCKMNT(nmp); tl += (NFSX_VERF / NFSX_UNSIGNED); if (nd->nd_repstat == 0 && *++tl != newnfs_true) /* Must be a synchronous copy. */ nd->nd_repstat = NFSERR_NOTSUPP; NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); error = nfsm_loadattr(nd, outnap); if (error == 0) *outattrflagp = NFS_LATTR_NOSHRINK; if (nd->nd_repstat == 0) *lenp = len; } else if (nd->nd_repstat == NFSERR_OFFLOADNOREQS) { /* * For the case where consecutive is not supported, but * synchronous is supported, we can try consecutive == false * by returning this error. Otherwise, return NFSERR_NOTSUPP, * since Copy cannot be done. */ if ((nd->nd_flag & ND_NOMOREDATA) == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (!consecutive || *++tl == newnfs_false) nd->nd_repstat = NFSERR_NOTSUPP; } else nd->nd_repstat = NFSERR_BADXDR; } if (error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * 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 nfsrpc_seek(vnode_t vp, off_t *offp, bool *eofp, int content, struct ucred *cred, struct nfsvattr *nap, int *attrflagp) { int error, expireret = 0, retrycnt; u_int32_t clidrev = 0; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *np = VTONFS(vp); struct nfsfh *nfhp = NULL; nfsv4stateid_t stateid; void *lckp; if (nmp->nm_clp != NULL) clidrev = nmp->nm_clp->nfsc_clientidrev; nfhp = np->n_fhp; retrycnt = 0; do { lckp = NULL; nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, NFSV4OPEN_ACCESSREAD, 0, cred, curthread, &stateid, &lckp); error = nfsrpc_seekrpc(vp, offp, &stateid, eofp, content, nap, attrflagp, cred); if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) nfscl_lockderef(lckp); 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_seek"); } 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_STALESTATEID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || error == NFSERR_BADSESSION || (error == NFSERR_OLDSTATEID && retrycnt < 20) || ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && expireret == 0 && clidrev != 0 && retrycnt < 4) || (error == NFSERR_OPENMODE && retrycnt < 4)); if (error && retrycnt >= 4) error = EIO; return (error); } /* * The seek RPC. */ static int nfsrpc_seekrpc(vnode_t vp, off_t *offp, nfsv4stateid_t *stateidp, bool *eofp, int content, struct nfsvattr *nap, int *attrflagp, struct ucred *cred) { uint32_t *tl; int error; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; nfsattrbit_t attrbits; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_SEEK, vp, cred); nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); txdr_hyper(*offp, tl); tl += 2; *tl++ = txdr_unsigned(content); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, curthread, cred); if (error != 0) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER); if (*tl++ == newnfs_true) *eofp = true; else *eofp = false; *offp = fxdr_hyper(tl); /* Just skip over Getattr op status. */ error = nfsm_loadattr(nd, nap); if (error == 0) *attrflagp = 1; } error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * The getextattr RPC. */ int nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp, struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; int error; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; nfsattrbit_t attrbits; uint32_t len, len2; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp, cred); nfsm_strtom(nd, name, strlen(name)); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, p, cred); if (error != 0) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(uint32_t, *tl); /* Sanity check lengths. */ if (uiop != NULL && len > 0 && len <= IOSIZE_MAX && uiop->uio_resid <= UINT32_MAX) { len2 = uiop->uio_resid; if (len2 >= len) error = nfsm_mbufuio(nd, uiop, len); else { error = nfsm_mbufuio(nd, uiop, len2); if (error == 0) { /* * nfsm_mbufuio() advances to a multiple * of 4, so round up len2 as well. Then * we need to advance over the rest of * the data, rounding up the remaining * length. */ len2 = NFSM_RNDUP(len2); len2 = NFSM_RNDUP(len - len2); if (len2 > 0) error = nfsm_advance(nd, len2, -1); } } } else if (uiop == NULL && len > 0) { /* Just wants the length and not the data. */ error = nfsm_advance(nd, NFSM_RNDUP(len), -1); } else if (len > 0) error = ENOATTR; if (error != 0) goto nfsmout; *lenp = len; /* Just skip over Getattr op status. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); error = nfsm_loadattr(nd, nap); if (error == 0) *attrflagp = 1; } if (error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * The setextattr RPC. */ int nfsrpc_setextattr(vnode_t vp, const char *name, struct uio *uiop, struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; int error; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; nfsattrbit_t attrbits; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_SETEXTATTR, vp, cred); if (uiop->uio_resid > nd->nd_maxreq) { /* nd_maxreq is set by NFSCL_REQSTART(). */ m_freem(nd->nd_mreq); return (EINVAL); } NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4SXATTR_EITHER); nfsm_strtom(nd, name, strlen(name)); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(uiop->uio_resid); error = nfsm_uiombuf(nd, uiop, uiop->uio_resid); if (error != 0) { m_freem(nd->nd_mreq); return (error); } NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, p, cred); if (error != 0) return (error); if (nd->nd_repstat == 0) { /* Just skip over the reply and Getattr op status. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); error = nfsm_loadattr(nd, nap); if (error == 0) *attrflagp = 1; } if (error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * The removeextattr RPC. */ int nfsrpc_rmextattr(vnode_t vp, const char *name, struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; int error; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; nfsattrbit_t attrbits; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_RMEXTATTR, vp, cred); nfsm_strtom(nd, name, strlen(name)); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, p, cred); if (error != 0) return (error); if (nd->nd_repstat == 0) { /* Just skip over the reply and Getattr op status. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); error = nfsm_loadattr(nd, nap); if (error == 0) *attrflagp = 1; } if (error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * The listextattr RPC. */ int nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop, size_t *lenp, bool *eofp, struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; int cnt, error, i, len; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; nfsattrbit_t attrbits; u_char c; *attrflagp = 0; NFSCL_REQSTART(nd, NFSPROC_LISTEXTATTR, vp, cred); NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); txdr_hyper(*cookiep, tl); tl += 2; *tl++ = txdr_unsigned(*lenp); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); nfsrv_putattrbit(nd, &attrbits); error = nfscl_request(nd, vp, p, cred); if (error != 0) return (error); *eofp = true; *lenp = 0; if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); *cookiep = fxdr_hyper(tl); tl += 2; cnt = fxdr_unsigned(int, *tl); if (cnt < 0) { error = EBADRPC; goto nfsmout; } for (i = 0; i < cnt; i++) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(int, *tl); if (len <= 0 || len > EXTATTR_MAXNAMELEN) { error = EBADRPC; goto nfsmout; } if (uiop == NULL) error = nfsm_advance(nd, NFSM_RNDUP(len), -1); else if (uiop->uio_resid >= len + 1) { c = len; error = uiomove(&c, sizeof(c), uiop); if (error == 0) error = nfsm_mbufuio(nd, uiop, len); } else { error = nfsm_advance(nd, NFSM_RNDUP(len), -1); *eofp = false; } if (error != 0) goto nfsmout; *lenp += (len + 1); } /* Get the eof and skip over the Getattr op status. */ NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED); /* * *eofp is set false above, because it wasn't able to copy * all of the reply. */ if (*eofp && *tl == 0) *eofp = false; error = nfsm_loadattr(nd, nap); if (error == 0) *attrflagp = 1; } if (error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); return (error); } /* * Split an mbuf list. For non-M_EXTPG mbufs, just use m_split(). */ static struct mbuf * nfsm_split(struct mbuf *mp, uint64_t xfer) { struct mbuf *m, *m2; vm_page_t pg; int i, j, left, pgno, plen, trim; char *cp, *cp2; if ((mp->m_flags & M_EXTPG) == 0) { m = m_split(mp, xfer, M_WAITOK); return (m); } /* Find the correct mbuf to split at. */ for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next) xfer -= m->m_len; if (m == NULL) return (NULL); /* If xfer == m->m_len, we can just split the mbuf list. */ if (xfer == m->m_len) { m2 = m->m_next; m->m_next = NULL; return (m2); } /* Find the page to split at. */ pgno = 0; left = xfer; do { if (pgno == 0) plen = m_epg_pagelen(m, 0, m->m_epg_1st_off); else plen = m_epg_pagelen(m, pgno, 0); if (left <= plen) break; left -= plen; pgno++; } while (pgno < m->m_epg_npgs); if (pgno == m->m_epg_npgs) panic("nfsm_split: eroneous ext_pgs mbuf"); m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs, 0); m2->m_epg_flags |= EPG_FLAG_ANON; /* * If left < plen, allocate a new page for the new mbuf * and copy the data after left in the page to this new * page. */ if (left < plen) { pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP | VM_ALLOC_WIRED); m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg); m2->m_epg_npgs = 1; /* Copy the data after left to the new page. */ trim = plen - left; cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]); if (pgno == 0) cp += m->m_epg_1st_off; cp += left; cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]); if (pgno == m->m_epg_npgs - 1) m2->m_epg_last_len = trim; else { cp2 += PAGE_SIZE - trim; m2->m_epg_1st_off = PAGE_SIZE - trim; m2->m_epg_last_len = m->m_epg_last_len; } memcpy(cp2, cp, trim); m2->m_len = trim; } else { m2->m_len = 0; m2->m_epg_last_len = m->m_epg_last_len; } /* Move the pages beyond pgno to the new mbuf. */ for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) { m2->m_epg_pa[j] = m->m_epg_pa[i]; /* Never moves page 0. */ m2->m_len += m_epg_pagelen(m, i, 0); } m2->m_epg_npgs = j; m->m_epg_npgs = pgno + 1; m->m_epg_last_len = left; m->m_len = xfer; m2->m_next = m->m_next; m->m_next = NULL; return (m2); } /* * Do the NFSv4.1 Bind Connection to Session. * Called from the reconnect layer of the krpc (sys/rpc/clnt_rc.c). */ void nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr) { struct nfscl_reconarg *rcp = (struct nfscl_reconarg *)arg; uint32_t res, *tl; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; struct rpc_callextra ext; struct timeval utimeout; enum clnt_stat stat; int error; nfscl_reqstart(nd, NFSPROC_BINDCONNTOSESS, NULL, NULL, 0, NULL, NULL, NFS_VER4, rcp->minorvers, NULL); NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); memcpy(tl, rcp->sessionid, NFSX_V4SESSIONID); tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; *tl++ = txdr_unsigned(NFSCDFC4_FORE_OR_BOTH); *tl = newnfs_false; memset(&ext, 0, sizeof(ext)); utimeout.tv_sec = 30; utimeout.tv_usec = 0; ext.rc_auth = authunix_create(cr); nd->nd_mrep = NULL; stat = CLNT_CALL_MBUF(cl, &ext, NFSV4PROC_COMPOUND, nd->nd_mreq, &nd->nd_mrep, utimeout); AUTH_DESTROY(ext.rc_auth); if (stat != RPC_SUCCESS) { printf("nfsrpc_bindconnsess: call failed stat=%d\n", stat); return; } if (nd->nd_mrep == NULL) { printf("nfsrpc_bindconnsess: no reply args\n"); return; } error = 0; newnfs_realign(&nd->nd_mrep, M_WAITOK); nd->nd_md = nd->nd_mrep; nd->nd_dpos = mtod(nd->nd_md, char *); NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); nd->nd_repstat = fxdr_unsigned(uint32_t, *tl++); if (nd->nd_repstat == NFSERR_OK) { res = fxdr_unsigned(uint32_t, *tl); if (res > 0 && (error = nfsm_advance(nd, NFSM_RNDUP(res), -1)) != 0) goto nfsmout; NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); tl += 3; if (!NFSBCMP(tl, rcp->sessionid, NFSX_V4SESSIONID)) { tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; res = fxdr_unsigned(uint32_t, *tl); if (res != NFSCDFS4_BOTH) printf("nfsrpc_bindconnsess: did not " "return FS4_BOTH\n"); } else printf("nfsrpc_bindconnsess: not same " "sessionid\n"); } else if (nd->nd_repstat != NFSERR_BADSESSION) printf("nfsrpc_bindconnsess: returned %d\n", nd->nd_repstat); nfsmout: if (error != 0) printf("nfsrpc_bindconnsess: reply bad xdr\n"); m_freem(nd->nd_mrep); } /* * nfs opeattr rpc */ int nfsrpc_openattr(struct nfsmount *nmp, struct vnode *vp, uint8_t *fhp, int fhlen, bool createit, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, struct nfsfh **nfhpp, int *attrflagp) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; nfsattrbit_t attrbits; int error = 0; *attrflagp = 0; nfscl_reqstart(nd, NFSPROC_OPENATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0, cred); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); if (createit) *tl = newnfs_true; else *tl = newnfs_false; NFSGETATTR_ATTRBIT(&attrbits); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_GETFH); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void)nfsrv_putattrbit(nd, &attrbits); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); error = nfsm_getfh(nd, nfhpp); if (error != 0) goto nfsmout; error = nfscl_postop_attr(nd, nap, attrflagp); } nfsmout: m_freem(nd->nd_mrep); if (error == 0 && nd->nd_repstat != 0) error = nd->nd_repstat; return (error); } /* * Do roughly what nfs_statfs() does for NFSv4, but when called with a shared * locked vnode. */ static void nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td) { struct nfsvattr nfsva; struct nfsfsinfo fs; struct nfsstatfs sb; struct mount *mp; struct nfsmount *nmp; uint32_t clone_blksize, lease; int attrflag, error; mp = vp->v_mount; nmp = VFSTONFS(mp); 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) { NFSLOCKCLSTATE(); if (nmp->nm_clp != NULL) nmp->nm_clp->nfsc_renew = NFSCL_RENEW(lease); NFSUNLOCKCLSTATE(); mtx_lock(&nmp->nm_mtx); 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_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 683d6099401e..e9ae91e046e7 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -1,4854 +1,4854 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * from nfs_vnops.c 8.16 (Berkeley) 5/27/95 */ #include /* * vnode op calls for Sun NFS version 2, 3 and 4 */ #include "opt_inet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KDTRACE_HOOKS #include dtrace_nfsclient_accesscache_flush_probe_func_t dtrace_nfscl_accesscache_flush_done_probe; uint32_t nfscl_accesscache_flush_done_id; dtrace_nfsclient_accesscache_get_probe_func_t dtrace_nfscl_accesscache_get_hit_probe, dtrace_nfscl_accesscache_get_miss_probe; uint32_t nfscl_accesscache_get_hit_id; uint32_t nfscl_accesscache_get_miss_id; dtrace_nfsclient_accesscache_load_probe_func_t dtrace_nfscl_accesscache_load_done_probe; uint32_t nfscl_accesscache_load_done_id; #endif /* !KDTRACE_HOOKS */ /* Defs */ #define TRUE 1 #define FALSE 0 extern struct nfsstatsv1 nfsstatsv1; extern int nfsrv_useacl; extern int nfscl_debuglevel; NFSCLSTATEMUTEX; MALLOC_DECLARE(M_NEWNFSREQ); static vop_read_t nfsfifo_read; static vop_write_t nfsfifo_write; static vop_close_t nfsfifo_close; static int nfs_setattrrpc(struct vnode *, struct vattr *, struct ucred *, struct thread *); static int nfs_get_namedattrdir(struct vnode *, struct componentname *, struct vnode **); static vop_lookup_t nfs_lookup; static vop_create_t nfs_create; static vop_mknod_t nfs_mknod; static vop_open_t nfs_open; static vop_pathconf_t nfs_pathconf; static vop_close_t nfs_close; static vop_access_t nfs_access; static vop_getattr_t nfs_getattr; static vop_setattr_t nfs_setattr; static vop_read_t nfs_read; static vop_fsync_t nfs_fsync; static vop_remove_t nfs_remove; static vop_link_t nfs_link; static vop_rename_t nfs_rename; static vop_mkdir_t nfs_mkdir; static vop_rmdir_t nfs_rmdir; static vop_symlink_t nfs_symlink; static vop_readdir_t nfs_readdir; static vop_strategy_t nfs_strategy; static int nfs_lookitup(struct vnode *, char *, int, struct ucred *, struct thread *, struct nfsnode **); static int nfs_sillyrename(struct vnode *, struct vnode *, struct componentname *); static vop_access_t nfsspec_access; static vop_readlink_t nfs_readlink; static vop_print_t nfs_print; static vop_advlock_t nfs_advlock; static vop_advlockasync_t nfs_advlockasync; static vop_getacl_t nfs_getacl; static vop_setacl_t nfs_setacl; static vop_advise_t nfs_advise; static vop_allocate_t nfs_allocate; static vop_deallocate_t nfs_deallocate; static vop_copy_file_range_t nfs_copy_file_range; static vop_ioctl_t nfs_ioctl; static vop_getextattr_t nfs_getextattr; static vop_setextattr_t nfs_setextattr; static vop_listextattr_t nfs_listextattr; static vop_deleteextattr_t nfs_deleteextattr; static vop_lock1_t nfs_lock; /* * Global vfs data structures for nfs */ static struct vop_vector newnfs_vnodeops_nosig = { .vop_default = &default_vnodeops, .vop_access = nfs_access, .vop_advlock = nfs_advlock, .vop_advlockasync = nfs_advlockasync, .vop_close = nfs_close, .vop_create = nfs_create, .vop_fsync = nfs_fsync, .vop_getattr = nfs_getattr, .vop_getpages = ncl_getpages, .vop_putpages = ncl_putpages, .vop_inactive = ncl_inactive, .vop_link = nfs_link, .vop_lock1 = nfs_lock, .vop_lookup = nfs_lookup, .vop_mkdir = nfs_mkdir, .vop_mknod = nfs_mknod, .vop_open = nfs_open, .vop_pathconf = nfs_pathconf, .vop_print = nfs_print, .vop_read = nfs_read, .vop_readdir = nfs_readdir, .vop_readlink = nfs_readlink, .vop_reclaim = ncl_reclaim, .vop_remove = nfs_remove, .vop_rename = nfs_rename, .vop_rmdir = nfs_rmdir, .vop_setattr = nfs_setattr, .vop_strategy = nfs_strategy, .vop_symlink = nfs_symlink, .vop_write = ncl_write, .vop_getacl = nfs_getacl, .vop_setacl = nfs_setacl, .vop_advise = nfs_advise, .vop_allocate = nfs_allocate, .vop_deallocate = nfs_deallocate, .vop_copy_file_range = nfs_copy_file_range, .vop_ioctl = nfs_ioctl, .vop_getextattr = nfs_getextattr, .vop_setextattr = nfs_setextattr, .vop_listextattr = nfs_listextattr, .vop_deleteextattr = nfs_deleteextattr, }; VFS_VOP_VECTOR_REGISTER(newnfs_vnodeops_nosig); static int nfs_vnodeops_bypass(struct vop_generic_args *a) { return (vop_sigdefer(&newnfs_vnodeops_nosig, a)); } struct vop_vector newnfs_vnodeops = { .vop_default = &default_vnodeops, .vop_bypass = nfs_vnodeops_bypass, }; VFS_VOP_VECTOR_REGISTER(newnfs_vnodeops); static struct vop_vector newnfs_fifoops_nosig = { .vop_default = &fifo_specops, .vop_access = nfsspec_access, .vop_close = nfsfifo_close, .vop_fsync = nfs_fsync, .vop_getattr = nfs_getattr, .vop_inactive = ncl_inactive, .vop_pathconf = nfs_pathconf, .vop_print = nfs_print, .vop_read = nfsfifo_read, .vop_reclaim = ncl_reclaim, .vop_setattr = nfs_setattr, .vop_write = nfsfifo_write, }; VFS_VOP_VECTOR_REGISTER(newnfs_fifoops_nosig); static int nfs_fifoops_bypass(struct vop_generic_args *a) { return (vop_sigdefer(&newnfs_fifoops_nosig, a)); } struct vop_vector newnfs_fifoops = { .vop_default = &default_vnodeops, .vop_bypass = nfs_fifoops_bypass, }; VFS_VOP_VECTOR_REGISTER(newnfs_fifoops); static int nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap); static int nfs_removerpc(struct vnode *dvp, struct vnode *vp, char *name, int namelen, struct ucred *cred, struct thread *td, bool silly); static void nfs_removestatus(struct vnode *vp, nfsremove_status file_status, bool silly, struct thread *td); static int nfs_renamerpc(struct vnode *fdvp, struct vnode *fvp, char *fnameptr, int fnamelen, struct vnode *tdvp, struct vnode *tvp, char *tnameptr, int tnamelen, bool silly, struct ucred *cred, struct thread *td); static int nfs_renameit(struct vnode *sdvp, struct vnode *svp, struct componentname *scnp, struct sillyrename *sp); /* * Global variables */ SYSCTL_DECL(_vfs_nfs); static int nfsaccess_cache_timeout = NFS_MAXATTRTIMO; SYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_timeout, CTLFLAG_RW, &nfsaccess_cache_timeout, 0, "NFS ACCESS cache timeout"); static int nfs_prime_access_cache = 0; SYSCTL_INT(_vfs_nfs, OID_AUTO, prime_access_cache, CTLFLAG_RW, &nfs_prime_access_cache, 0, "Prime NFS ACCESS cache when fetching attributes"); static int newnfs_commit_on_close = 0; SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_on_close, CTLFLAG_RW, &newnfs_commit_on_close, 0, "write+commit on close, else only write"); static int nfs_clean_pages_on_close = 1; SYSCTL_INT(_vfs_nfs, OID_AUTO, clean_pages_on_close, CTLFLAG_RW, &nfs_clean_pages_on_close, 0, "NFS clean dirty pages on close"); int newnfs_directio_enable = 0; SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_directio_enable, CTLFLAG_RW, &newnfs_directio_enable, 0, "Enable NFS directio"); int nfs_keep_dirty_on_error; SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_keep_dirty_on_error, CTLFLAG_RW, &nfs_keep_dirty_on_error, 0, "Retry pageout if error returned"); /* * This sysctl allows other processes to mmap a file that has been opened * O_DIRECT by a process. In general, having processes mmap the file while * Direct IO is in progress can lead to Data Inconsistencies. But, we allow * this by default to prevent DoS attacks - to prevent a malicious user from * opening up files O_DIRECT preventing other users from mmap'ing these * files. "Protected" environments where stricter consistency guarantees are * required can disable this knob. The process that opened the file O_DIRECT * cannot mmap() the file, because mmap'ed IO on an O_DIRECT open() is not * meaningful. */ int newnfs_directio_allow_mmap = 1; SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_directio_allow_mmap, CTLFLAG_RW, &newnfs_directio_allow_mmap, 0, "Enable mmaped IO on file with O_DIRECT opens"); static uint64_t nfs_maxalloclen = 64 * 1024 * 1024; SYSCTL_U64(_vfs_nfs, OID_AUTO, maxalloclen, CTLFLAG_RW, &nfs_maxalloclen, 0, "NFS max allocate/deallocate length"); #define NFSACCESS_ALL (NFSACCESS_READ | NFSACCESS_MODIFY \ | NFSACCESS_EXTEND | NFSACCESS_EXECUTE \ | NFSACCESS_DELETE | NFSACCESS_LOOKUP) /* * SMP Locking Note : * The list of locks after the description of the lock is the ordering * of other locks acquired with the lock held. * np->n_mtx : Protects the fields in the nfsnode. VM Object Lock VI_MTX (acquired indirectly) * nmp->nm_mtx : Protects the fields in the nfsmount. rep->r_mtx * ncl_iod_mutex : Global lock, protects shared nfsiod state. * nfs_reqq_mtx : Global lock, protects the nfs_reqq list. nmp->nm_mtx rep->r_mtx * rep->r_mtx : Protects the fields in an nfsreq. */ static int nfs_lock(struct vop_lock1_args *ap) { struct vnode *vp; struct nfsnode *np; u_quad_t nsize; int error, lktype; bool onfault; vp = ap->a_vp; lktype = ap->a_flags & LK_TYPE_MASK; error = VOP_LOCK1_APV(&default_vnodeops, ap); if (error != 0 || vp->v_op != &newnfs_vnodeops) return (error); np = VTONFS(vp); if (np == NULL) return (0); NFSLOCKNODE(np); if ((np->n_flag & NVNSETSZSKIP) == 0 || (lktype != LK_SHARED && lktype != LK_EXCLUSIVE && lktype != LK_UPGRADE && lktype != LK_TRYUPGRADE)) { NFSUNLOCKNODE(np); return (0); } onfault = (ap->a_flags & LK_EATTR_MASK) == LK_NOWAIT && (ap->a_flags & LK_INIT_MASK) == LK_CANRECURSE && (lktype == LK_SHARED || lktype == LK_EXCLUSIVE); if (onfault && vp->v_vnlock->lk_recurse == 0) { /* * Force retry in vm_fault(), to make the lock request * sleepable, which allows us to piggy-back the * sleepable call to vnode_pager_setsize(). */ NFSUNLOCKNODE(np); VOP_UNLOCK(vp); return (EBUSY); } if ((ap->a_flags & LK_NOWAIT) != 0 || (lktype == LK_SHARED && vp->v_vnlock->lk_recurse > 0)) { NFSUNLOCKNODE(np); return (0); } if (lktype == LK_SHARED) { NFSUNLOCKNODE(np); VOP_UNLOCK(vp); ap->a_flags &= ~(LK_TYPE_MASK | LK_INTERLOCK); ap->a_flags |= LK_EXCLUSIVE; error = VOP_LOCK1_APV(&default_vnodeops, ap); if (error != 0 || vp->v_op != &newnfs_vnodeops) return (error); if (vp->v_data == NULL) goto downgrade; MPASS(vp->v_data == np); NFSLOCKNODE(np); if ((np->n_flag & NVNSETSZSKIP) == 0) { NFSUNLOCKNODE(np); goto downgrade; } } np->n_flag &= ~NVNSETSZSKIP; nsize = np->n_size; NFSUNLOCKNODE(np); vnode_pager_setsize(vp, nsize); downgrade: if (lktype == LK_SHARED) { ap->a_flags &= ~(LK_TYPE_MASK | LK_INTERLOCK); ap->a_flags |= LK_DOWNGRADE; (void)VOP_LOCK1_APV(&default_vnodeops, ap); } return (0); } static int nfs34_access_otw(struct vnode *vp, int wmode, struct thread *td, struct ucred *cred, u_int32_t *retmode) { int error = 0, attrflag, i, lrupos; u_int32_t rmode; struct nfsnode *np = VTONFS(vp); struct nfsvattr nfsva; error = nfsrpc_accessrpc(vp, wmode, cred, td, &nfsva, &attrflag, &rmode); if (attrflag) (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (!error) { lrupos = 0; NFSLOCKNODE(np); for (i = 0; i < NFS_ACCESSCACHESIZE; i++) { if (np->n_accesscache[i].uid == cred->cr_uid) { np->n_accesscache[i].mode = rmode; np->n_accesscache[i].stamp = time_second; break; } if (i > 0 && np->n_accesscache[i].stamp < np->n_accesscache[lrupos].stamp) lrupos = i; } if (i == NFS_ACCESSCACHESIZE) { np->n_accesscache[lrupos].uid = cred->cr_uid; np->n_accesscache[lrupos].mode = rmode; np->n_accesscache[lrupos].stamp = time_second; } NFSUNLOCKNODE(np); if (retmode != NULL) *retmode = rmode; KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, cred->cr_uid, rmode, 0); } else if (NFS_ISV4(vp)) { error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); } #ifdef KDTRACE_HOOKS if (error != 0) KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, cred->cr_uid, 0, error); #endif return (error); } /* * nfs access vnode op. * For nfs version 2, just return ok. File accesses may fail later. * For nfs version 3, use the access rpc to check accessibility. If file modes * are changed on the server, accesses might still fail later. */ static int nfs_access(struct vop_access_args *ap) { struct vnode *vp = ap->a_vp; int error = 0, i, gotahit; u_int32_t mode, wmode, rmode; int v34 = NFS_ISV34(vp); struct nfsnode *np = VTONFS(vp); /* * Disallow write attempts on filesystems mounted read-only; * unless the file is a socket, fifo, or a block or character * device resident on the filesystem. */ if ((ap->a_accmode & (VWRITE | VAPPEND | VWRITE_NAMED_ATTRS | VDELETE_CHILD | VWRITE_ATTRIBUTES | VDELETE | VWRITE_ACL | VWRITE_OWNER)) != 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) != 0) { switch (vp->v_type) { case VREG: case VDIR: case VLNK: return (EROFS); default: break; } } /* * For NFSv4, check for a delegation with an Allow ACE, to see * if that permits access. */ if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOCTO) != 0) { error = nfscl_delegacecheck(vp, ap->a_accmode, ap->a_cred); if (error == 0) return (error); error = 0; } /* * For nfs v3 or v4, check to see if we have done this recently, and if * so return our cached result instead of making an ACCESS call. * If not, do an access rpc, otherwise you are stuck emulating * ufs_access() locally using the vattr. This may not be correct, * since the server may apply other access criteria such as * client uid-->server uid mapping that we do not know about. */ if (v34) { if (ap->a_accmode & VREAD) mode = NFSACCESS_READ; else mode = 0; if (vp->v_type != VDIR) { if (ap->a_accmode & VWRITE) mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); if (ap->a_accmode & VAPPEND) mode |= NFSACCESS_EXTEND; if (ap->a_accmode & VEXEC) mode |= NFSACCESS_EXECUTE; if (ap->a_accmode & VDELETE) mode |= NFSACCESS_DELETE; } else { if (ap->a_accmode & VWRITE) mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); if (ap->a_accmode & VAPPEND) mode |= NFSACCESS_EXTEND; if (ap->a_accmode & VEXEC) mode |= NFSACCESS_LOOKUP; if (ap->a_accmode & VDELETE) mode |= NFSACCESS_DELETE; if (ap->a_accmode & VDELETE_CHILD) mode |= NFSACCESS_MODIFY; } /* XXX safety belt, only make blanket request if caching */ if (nfsaccess_cache_timeout > 0) { wmode = NFSACCESS_READ | NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_EXECUTE | NFSACCESS_DELETE | NFSACCESS_LOOKUP; } else { wmode = mode; } /* * Does our cached result allow us to give a definite yes to * this request? */ gotahit = 0; NFSLOCKNODE(np); for (i = 0; i < NFS_ACCESSCACHESIZE; i++) { if (ap->a_cred->cr_uid == np->n_accesscache[i].uid) { if (time_second < (np->n_accesscache[i].stamp + nfsaccess_cache_timeout) && (np->n_accesscache[i].mode & mode) == mode) { NFSINCRGLOBAL(nfsstatsv1.accesscache_hits); gotahit = 1; } break; } } NFSUNLOCKNODE(np); #ifdef KDTRACE_HOOKS if (gotahit != 0) KDTRACE_NFS_ACCESSCACHE_GET_HIT(vp, ap->a_cred->cr_uid, mode); else KDTRACE_NFS_ACCESSCACHE_GET_MISS(vp, ap->a_cred->cr_uid, mode); #endif if (gotahit == 0) { /* * Either a no, or a don't know. Go to the wire. */ NFSINCRGLOBAL(nfsstatsv1.accesscache_misses); error = nfs34_access_otw(vp, wmode, ap->a_td, ap->a_cred, &rmode); if (!error && (rmode & mode) != mode) error = EACCES; } return (error); } else { if ((error = nfsspec_access(ap)) != 0) { return (error); } /* * Attempt to prevent a mapped root from accessing a file * which it shouldn't. We try to read a byte from the file * if the user is root and the file is not zero length. * After calling nfsspec_access, we should have the correct * file size cached. */ NFSLOCKNODE(np); if (ap->a_cred->cr_uid == 0 && (ap->a_accmode & VREAD) && VTONFS(vp)->n_size > 0) { struct iovec aiov; struct uio auio; char buf[1]; NFSUNLOCKNODE(np); aiov.iov_base = buf; aiov.iov_len = 1; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_resid = 1; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_READ; auio.uio_td = ap->a_td; if (vp->v_type == VREG) error = ncl_readrpc(vp, &auio, ap->a_cred); else if (vp->v_type == VDIR) { char* bp; bp = malloc(NFS_DIRBLKSIZ, M_TEMP, M_WAITOK); aiov.iov_base = bp; aiov.iov_len = auio.uio_resid = NFS_DIRBLKSIZ; error = ncl_readdirrpc(vp, &auio, ap->a_cred, ap->a_td); free(bp, M_TEMP); } else if (vp->v_type == VLNK) error = ncl_readlinkrpc(vp, &auio, ap->a_cred); else error = EACCES; } else NFSUNLOCKNODE(np); return (error); } } /* * nfs open vnode op * Check to see if the type is ok * and that deletion is not in progress. * For paged in text files, you will need to flush the page cache * if consistency is lost. */ /* ARGSUSED */ static int nfs_open(struct vop_open_args *ap) { struct vnode *vp = ap->a_vp; struct nfsnode *np = VTONFS(vp); struct vattr vattr; int error; int fmode = ap->a_mode; struct ucred *cred; vm_object_t obj; if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) return (EOPNOTSUPP); /* * For NFSv4, we need to do the Open Op before cache validation, * so that we conform to RFC3530 Sec. 9.3.1. */ if (NFS_ISV4(vp)) { error = nfsrpc_open(vp, fmode, ap->a_cred, ap->a_td); if (error) { error = nfscl_maperr(ap->a_td, error, (uid_t)0, (gid_t)0); return (error); } } /* * Now, if this Open will be doing reading, re-validate/flush the * cache, so that Close/Open coherency is maintained. */ NFSLOCKNODE(np); if (np->n_flag & NMODIFIED) { NFSUNLOCKNODE(np); if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(vp)) return (EBADF); } error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); if (error == EINTR || error == EIO) { if (NFS_ISV4(vp)) (void) nfsrpc_close(vp, 0, ap->a_td); return (error); } NFSLOCKNODE(np); np->n_attrstamp = 0; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); if (vp->v_type == VDIR) np->n_direofoffset = 0; NFSUNLOCKNODE(np); error = VOP_GETATTR(vp, &vattr, ap->a_cred); if (error) { if (NFS_ISV4(vp)) (void) nfsrpc_close(vp, 0, ap->a_td); return (error); } NFSLOCKNODE(np); np->n_mtime = vattr.va_mtime; if (NFS_ISV4(vp)) np->n_change = vattr.va_filerev; } else { NFSUNLOCKNODE(np); error = VOP_GETATTR(vp, &vattr, ap->a_cred); if (error) { if (NFS_ISV4(vp)) (void) nfsrpc_close(vp, 0, ap->a_td); return (error); } NFSLOCKNODE(np); if ((NFS_ISV4(vp) && np->n_change != vattr.va_filerev) || NFS_TIMESPEC_COMPARE(&np->n_mtime, &vattr.va_mtime)) { if (vp->v_type == VDIR) np->n_direofoffset = 0; NFSUNLOCKNODE(np); if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(vp)) return (EBADF); } error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); if (error == EINTR || error == EIO) { if (NFS_ISV4(vp)) (void) nfsrpc_close(vp, 0, ap->a_td); return (error); } NFSLOCKNODE(np); np->n_mtime = vattr.va_mtime; if (NFS_ISV4(vp)) np->n_change = vattr.va_filerev; } } /* * If the object has >= 1 O_DIRECT active opens, we disable caching. */ if (newnfs_directio_enable && (fmode & O_DIRECT) && (vp->v_type == VREG)) { if (np->n_directio_opens == 0) { NFSUNLOCKNODE(np); if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(vp)) return (EBADF); } error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); if (error) { if (NFS_ISV4(vp)) (void) nfsrpc_close(vp, 0, ap->a_td); return (error); } NFSLOCKNODE(np); np->n_flag |= NNONCACHE; } np->n_directio_opens++; } /* If opened for writing via NFSv4.1 or later, mark that for pNFS. */ if (NFSHASPNFS(VFSTONFS(vp->v_mount)) && (fmode & FWRITE) != 0) np->n_flag |= NWRITEOPENED; /* * If this is an open for writing, capture a reference to the * credentials, so they can be used by ncl_putpages(). Using * these write credentials is preferable to the credentials of * whatever thread happens to be doing the VOP_PUTPAGES() since * the write RPCs are less likely to fail with EACCES. */ if ((fmode & FWRITE) != 0) { cred = np->n_writecred; np->n_writecred = crhold(ap->a_cred); } else cred = NULL; NFSUNLOCKNODE(np); if (cred != NULL) crfree(cred); vnode_create_vobject(vp, vattr.va_size, ap->a_td); /* * If the text file has been mmap'd, flush any dirty pages to the * buffer cache and then... * Make sure all writes are pushed to the NFS server. If this is not * done, the modify time of the file can change while the text * file is being executed. This will cause the process that is * executing the text file to be terminated. */ if (vp->v_writecount <= -1) { if ((obj = vp->v_object) != NULL && vm_object_mightbedirty(obj)) { if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(vp)) return (EBADF); } vnode_pager_clean_sync(vp); } /* Now, flush the buffer cache. */ ncl_flush(vp, MNT_WAIT, curthread, 0, 0); /* And, finally, make sure that n_mtime is up to date. */ np = VTONFS(vp); NFSLOCKNODE(np); np->n_mtime = np->n_vattr.na_mtime; NFSUNLOCKNODE(np); } return (0); } /* * nfs close vnode op * What an NFS client should do upon close after writing is a debatable issue. * Most NFS clients push delayed writes to the server upon close, basically for * two reasons: * 1 - So that any write errors may be reported back to the client process * doing the close system call. By far the two most likely errors are * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure. * 2 - To put a worst case upper bound on cache inconsistency between * multiple clients for the file. * There is also a consistency problem for Version 2 of the protocol w.r.t. * not being able to tell if other clients are writing a file concurrently, * since there is no way of knowing if the changed modify time in the reply * is only due to the write for this client. * (NFS Version 3 provides weak cache consistency data in the reply that * should be sufficient to detect and handle this case.) * * The current code does the following: * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers * for NFS Version 3 - flush dirty buffers to the server but don't invalidate * or commit them (this satisfies 1 and 2 except for the * case where the server crashes after this close but * before the commit RPC, which is felt to be "good * enough". Changing the last argument to ncl_flush() to * a 1 would force a commit operation, if it is felt a * commit is necessary now. * for NFS Version 4 - flush the dirty buffers and commit them, if * nfscl_mustflush() says this is necessary. * It is necessary if there is no write delegation held, * in order to satisfy open/close coherency. * If the file isn't cached on local stable storage, * it may be necessary in order to detect "out of space" * errors from the server, if the write delegation * issued by the server doesn't allow the file to grow. */ /* ARGSUSED */ static int nfs_close(struct vop_close_args *ap) { struct vnode *vp = ap->a_vp; struct nfsnode *np = VTONFS(vp); struct nfsvattr nfsva; struct ucred *cred; int error = 0, ret, localcred = 0; int fmode = ap->a_fflag; struct nfsmount *nmp; if (NFSCL_FORCEDISM(vp->v_mount)) return (0); nmp = VFSTONFS(vp->v_mount); /* * During shutdown, a_cred isn't valid, so just use root. */ if (ap->a_cred == NOCRED) { cred = newnfs_getcred(); localcred = 1; } else { cred = ap->a_cred; } if (vp->v_type == VREG) { /* * Examine and clean dirty pages, regardless of NMODIFIED. * This closes a major hole in close-to-open consistency. * We want to push out all dirty pages (and buffers) on * close, regardless of whether they were dirtied by * mmap'ed writes or via write(). */ if (nfs_clean_pages_on_close && vp->v_object) { if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(vp) && ap->a_fflag != FNONBLOCK) return (EBADF); } vnode_pager_clean_async(vp); } NFSLOCKNODE(np); if (np->n_flag & NMODIFIED) { NFSUNLOCKNODE(np); if (NFS_ISV3(vp)) { /* * Under NFSv3 we have dirty buffers to dispose of. We * must flush them to the NFS server. We have the option * of waiting all the way through the commit rpc or just * waiting for the initial write. The default is to only * wait through the initial write so the data is in the * server's cache, which is roughly similar to the state * a standard disk subsystem leaves the file in on close(). * * We cannot clear the NMODIFIED bit in np->n_flag due to * potential races with other processes, and certainly * cannot clear it if we don't commit. * These races occur when there is no longer the old * traditional vnode locking implemented for Vnode Ops. */ int cm = newnfs_commit_on_close ? 1 : 0; if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(vp) && ap->a_fflag != FNONBLOCK) return (EBADF); } error = ncl_flush(vp, MNT_WAIT, ap->a_td, cm, 0); /* np->n_flag &= ~NMODIFIED; */ } else if (NFS_ISV4(vp)) { if (!NFSHASNFSV4N(nmp) || (nmp->nm_flag & NFSMNT_NOCTO) == 0 || nfscl_mustflush(vp) != 0) { int cm = newnfs_commit_on_close ? 1 : 0; if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(vp) && ap->a_fflag != FNONBLOCK) return (EBADF); } error = ncl_flush(vp, MNT_WAIT, ap->a_td, cm, 0); /* * as above w.r.t races when clearing * NMODIFIED. * np->n_flag &= ~NMODIFIED; */ } } else { if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(vp) && ap->a_fflag != FNONBLOCK) return (EBADF); } error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); } NFSLOCKNODE(np); } /* * Invalidate the attribute cache in all cases. * An open is going to fetch fresh attrs any way, other procs * on this node that have file open will be forced to do an * otw attr fetch, but this is safe. * --> A user found that their RPC count dropped by 20% when * this was commented out and I can't see any requirement * for it, so I've disabled it when negative lookups are * enabled. (What does this have to do with negative lookup * caching? Well nothing, except it was reported by the * same user that needed negative lookup caching and I wanted * there to be a way to disable it to see if it * is the cause of some caching/coherency issue that might * crop up.) */ if (nmp->nm_negnametimeo == 0) { np->n_attrstamp = 0; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); } if (np->n_flag & NWRITEERR) { np->n_flag &= ~NWRITEERR; error = np->n_error; } NFSUNLOCKNODE(np); } if (NFS_ISV4(vp)) { /* * Get attributes so "change" is up to date. */ if (error == 0 && nfscl_nodeleg(vp, 0) != 0 && vp->v_type == VREG && (nmp->nm_flag & NFSMNT_NOCTO) == 0) { ret = nfsrpc_getattr(vp, cred, ap->a_td, &nfsva); if (!ret) { np->n_change = nfsva.na_filerev; (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 0); } } /* * and do the close. */ ret = nfsrpc_close(vp, 0, ap->a_td); if (!error && ret) error = ret; if (error) error = nfscl_maperr(ap->a_td, error, (uid_t)0, (gid_t)0); } if (newnfs_directio_enable && (fmode & O_DIRECT) && (vp->v_type == VREG)) { NFSLOCKNODE(np); KASSERT((np->n_directio_opens > 0), ("nfs_close: unexpectedly value (0) of n_directio_opens\n")); np->n_directio_opens--; if (np->n_directio_opens == 0) np->n_flag &= ~NNONCACHE; NFSUNLOCKNODE(np); } if (localcred) NFSFREECRED(cred); return (error); } /* * nfs getattr call from vfs. */ static int nfs_getattr(struct vop_getattr_args *ap) { struct vnode *vp = ap->a_vp; struct thread *td = curthread; /* XXX */ struct nfsnode *np = VTONFS(vp); int error = 0; struct nfsvattr nfsva; struct vattr *vap = ap->a_vap; struct vattr vattr; struct nfsmount *nmp; nmp = VFSTONFS(vp->v_mount); /* * Update local times for special files. */ NFSLOCKNODE(np); if (np->n_flag & (NACC | NUPD)) np->n_flag |= NCHG; NFSUNLOCKNODE(np); /* * First look in the cache. * For "syskrb5" mounts, nm_fhsize might still be zero and * cached attributes should be ignored. */ if (nmp->nm_fhsize > 0 && ncl_getattrcache(vp, &vattr) == 0) { ncl_copy_vattr(vp, vap, &vattr); /* * Get the local modify time for the case of a write * delegation. */ nfscl_deleggetmodtime(vp, &vap->va_mtime); return (0); } if (NFS_ISV34(vp) && nfs_prime_access_cache && nfsaccess_cache_timeout > 0) { NFSINCRGLOBAL(nfsstatsv1.accesscache_misses); nfs34_access_otw(vp, NFSACCESS_ALL, td, ap->a_cred, NULL); if (ncl_getattrcache(vp, ap->a_vap) == 0) { nfscl_deleggetmodtime(vp, &ap->a_vap->va_mtime); return (0); } } error = nfsrpc_getattr(vp, ap->a_cred, td, &nfsva); if (error == 0) error = nfscl_loadattrcache(&vp, &nfsva, vap, 0, 0); if (!error) { /* * Get the local modify time for the case of a write * delegation. */ nfscl_deleggetmodtime(vp, &vap->va_mtime); } else if (NFS_ISV4(vp)) { error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); } return (error); } /* * nfs setattr call. */ static int nfs_setattr(struct vop_setattr_args *ap) { struct vnode *vp = ap->a_vp; struct nfsnode *np = VTONFS(vp); struct thread *td = curthread; /* XXX */ struct vattr *vap = ap->a_vap; int error = 0; u_quad_t tsize; struct timespec ts; struct nfsmount *nmp; #ifndef nolint tsize = (u_quad_t)0; #endif /* * Only setting of UF_HIDDEN and UF_SYSTEM are supported and * only for NFSv4 servers that support them. */ nmp = VFSTONFS(vp->v_mount); if (vap->va_flags != VNOVAL && (!NFSHASNFSV4(nmp) || (vap->va_flags & ~(UF_HIDDEN | UF_SYSTEM)) != 0 || ((vap->va_flags & UF_HIDDEN) != 0 && !NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_HIDDEN)) || ((vap->va_flags & UF_SYSTEM) != 0 && !NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_SYSTEM)))) return (EOPNOTSUPP); /* * Disallow write attempts if the filesystem is mounted read-only. */ if ((vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_birthtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && (vp->v_mount->mnt_flag & MNT_RDONLY)) return (EROFS); if (vap->va_size != VNOVAL) { switch (vp->v_type) { case VDIR: return (EISDIR); case VCHR: case VBLK: case VSOCK: case VFIFO: if (vap->va_mtime.tv_sec == VNOVAL && vap->va_atime.tv_sec == VNOVAL && vap->va_birthtime.tv_sec == VNOVAL && vap->va_mode == (mode_t)VNOVAL && vap->va_uid == (uid_t)VNOVAL && vap->va_gid == (gid_t)VNOVAL) return (0); vap->va_size = VNOVAL; break; default: /* * Disallow write attempts if the filesystem is * mounted read-only. */ if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); /* * We run vnode_pager_setsize() early (why?), * we must set np->n_size now to avoid vinvalbuf * V_SAVE races that might setsize a lower * value. */ NFSLOCKNODE(np); tsize = np->n_size; NFSUNLOCKNODE(np); error = ncl_meta_setsize(vp, td, vap->va_size); NFSLOCKNODE(np); if (np->n_flag & NMODIFIED) { tsize = np->n_size; NFSUNLOCKNODE(np); error = ncl_vinvalbuf(vp, vap->va_size == 0 ? 0 : V_SAVE, td, 1); if (error != 0) { vnode_pager_setsize(vp, tsize); return (error); } /* * Call nfscl_delegmodtime() to set the modify time * locally, as required. */ nfscl_delegmodtime(vp, NULL); } else NFSUNLOCKNODE(np); /* * np->n_size has already been set to vap->va_size * in ncl_meta_setsize(). We must set it again since * nfs_loadattrcache() could be called through * ncl_meta_setsize() and could modify np->n_size. */ NFSLOCKNODE(np); np->n_vattr.na_size = np->n_size = vap->va_size; NFSUNLOCKNODE(np); } } else { NFSLOCKNODE(np); if ((vap->va_mtime.tv_sec != VNOVAL || vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) && vp->v_type == VREG) { NFSUNLOCKNODE(np); error = ncl_vinvalbuf(vp, V_SAVE, td, 1); if (error == EINTR || error == EIO) return (error); } else NFSUNLOCKNODE(np); } error = nfs_setattrrpc(vp, vap, ap->a_cred, td); if (vap->va_size != VNOVAL) { if (error == 0) { nanouptime(&ts); NFSLOCKNODE(np); np->n_localmodtime = ts; NFSUNLOCKNODE(np); } else { NFSLOCKNODE(np); np->n_size = np->n_vattr.na_size = tsize; vnode_pager_setsize(vp, tsize); NFSUNLOCKNODE(np); } } if (vap->va_mtime.tv_sec != VNOVAL && error == 0) nfscl_delegmodtime(vp, &vap->va_mtime); return (error); } /* * Do an nfs setattr rpc. */ static int nfs_setattrrpc(struct vnode *vp, struct vattr *vap, struct ucred *cred, struct thread *td) { struct nfsnode *np = VTONFS(vp); int error, ret, attrflag, i; struct nfsvattr nfsva; if (NFS_ISV34(vp)) { NFSLOCKNODE(np); for (i = 0; i < NFS_ACCESSCACHESIZE; i++) np->n_accesscache[i].stamp = 0; np->n_flag |= NDELEGMOD; NFSUNLOCKNODE(np); KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp); } error = nfsrpc_setattr(vp, vap, NULL, cred, td, &nfsva, &attrflag); if (attrflag) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (ret && !error) error = ret; } if (error && NFS_ISV4(vp)) error = nfscl_maperr(td, error, vap->va_uid, vap->va_gid); return (error); } /* * Get a named attribute directory for the vnode. */ static int nfs_get_namedattrdir(struct vnode *vp, struct componentname *cnp, struct vnode **vpp) { struct nfsfh *nfhp; struct nfsnode *np; struct vnode *newvp; struct nfsvattr nfsva; int attrflag, error; attrflag = 0; *vpp = NULL; np = VTONFS(vp); error = nfsrpc_openattr(VFSTONFS(vp->v_mount), vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, (cnp->cn_flags & CREATENAMED), cnp->cn_cred, curthread, &nfsva, &nfhp, &attrflag); if (error == NFSERR_NOTSUPP) error = ENOATTR; if (error == 0) error = nfscl_nget(vp->v_mount, vp, nfhp, cnp, curthread, &np, cnp->cn_lkflags); if (error != 0) return (error); newvp = NFSTOV(np); vn_irflag_set_cond(newvp, VIRF_NAMEDDIR); if (attrflag != 0) (void)nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); *vpp = newvp; return (0); } /* * nfs lookup call, one step at a time... * First look in cache * If not found, unlock the directory nfsnode and do the rpc */ static int nfs_lookup(struct vop_lookup_args *ap) { struct componentname *cnp = ap->a_cnp; struct vnode *dvp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; struct mount *mp = dvp->v_mount; uint64_t flags = cnp->cn_flags; struct vnode *newvp; struct nfsmount *nmp; struct nfsnode *np, *newnp; int error = 0, attrflag, dattrflag, ltype, ncticks; struct thread *td = curthread; struct nfsfh *nfhp; struct nfsvattr dnfsva, nfsva; struct vattr vattr; struct timespec nctime, ts; uint32_t openmode; bool is_nameddir, needs_nameddir, opennamed; dattrflag = 0; *vpp = NULL; nmp = VFSTONFS(mp); opennamed = (flags & (OPENNAMED | ISLASTCN)) == (OPENNAMED | ISLASTCN); if (opennamed && (!NFSHASNFSV4(nmp) || !NFSHASNFSV4N(nmp))) return (ENOATTR); is_nameddir = (vn_irflag_read(dvp) & VIRF_NAMEDDIR) != 0; if ((is_nameddir && (flags & ISLASTCN) == 0 && (cnp->cn_namelen > 1 || *cnp->cn_nameptr != '.')) || (opennamed && !is_nameddir && (flags & ISDOTDOT) != 0)) return (ENOATTR); if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); np = VTONFS(dvp); needs_nameddir = false; if (opennamed || is_nameddir) { cnp->cn_flags &= ~MAKEENTRY; if (!is_nameddir) needs_nameddir = true; } /* * If the named attribute directory is needed, acquire it now. */ newvp = NULL; if (needs_nameddir) { KASSERT(np->n_v4 == NULL, ("nfs_lookup: O_NAMEDATTR when" " n_v4 not NULL")); error = nfs_get_namedattrdir(dvp, cnp, &newvp); if (error != 0) goto handle_error; if (cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.') { *vpp = newvp; return (0); } dvp = newvp; np = VTONFS(dvp); newvp = NULL; } else if (opennamed && cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.') { - VREF(dvp); + vref(dvp); *vpp = dvp; return (0); } if (dvp->v_type != VDIR) return (ENOTDIR); /* For NFSv4, wait until any remove is done. */ NFSLOCKNODE(np); while (NFSHASNFSV4(nmp) && (np->n_flag & NREMOVEINPROG)) { np->n_flag |= NREMOVEWANT; (void) msleep((caddr_t)np, &np->n_mtx, PZERO, "nfslkup", 0); } NFSUNLOCKNODE(np); error = vn_dir_check_exec(dvp, cnp); if (error != 0) return (error); if (!opennamed && !is_nameddir) { error = cache_lookup(dvp, vpp, cnp, &nctime, &ncticks); if (error > 0 && error != ENOENT) return (error); if (error == -1) { /* * Lookups of "." are special and always return the * current directory. cache_lookup() already handles * associated locking bookkeeping, etc. */ if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { return (0); } /* * We only accept a positive hit in the cache if the * change time of the file matches our cached copy. * Otherwise, we discard the cache entry and fallback * to doing a lookup RPC. We also only trust cache * entries for less than nm_nametimeo seconds. * * To better handle stale file handles and attributes, * clear the attribute cache of this node if it is a * leaf component, part of an open() call, and not * locally modified before fetching the attributes. * This should allow stale file handles to be detected * here where we can fall back to a LOOKUP RPC to * recover rather than having nfs_open() detect the * stale file handle and failing open(2) with ESTALE. */ newvp = *vpp; newnp = VTONFS(newvp); if (!(nmp->nm_flag & NFSMNT_NOCTO) && (flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) && !(newnp->n_flag & NMODIFIED)) { NFSLOCKNODE(newnp); newnp->n_attrstamp = 0; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp); NFSUNLOCKNODE(newnp); } if (nfscl_nodeleg(newvp, 0) == 0 || ((u_int)(ticks - ncticks) < (nmp->nm_nametimeo * hz) && VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 && timespeccmp(&vattr.va_ctime, &nctime, ==))) { NFSINCRGLOBAL(nfsstatsv1.lookupcache_hits); return (0); } cache_purge(newvp); if (dvp != newvp) vput(newvp); else vrele(newvp); *vpp = NULL; } else if (error == ENOENT) { if (VN_IS_DOOMED(dvp)) return (ENOENT); /* * We only accept a negative hit in the cache if the * modification time of the parent directory matches * the cached copy in the name cache entry. * Otherwise, we discard all of the negative cache * entries for this directory. We also only trust * negative cache entries for up to nm_negnametimeo * seconds. */ if ((u_int)(ticks - ncticks) < (nmp->nm_negnametimeo * hz) && VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 && timespeccmp(&vattr.va_mtime, &nctime, ==)) { NFSINCRGLOBAL(nfsstatsv1.lookupcache_hits); return (ENOENT); } cache_purge_negative(dvp); } } openmode = 0; #if 0 /* * The use of LookupOpen breaks some builds. It is disabled * until that is fixed. */ /* * If this an NFSv4.1/4.2 mount using the "oneopenown" mount * option, it is possible to do the Open operation in the same * compound as Lookup, so long as delegations are not being * issued. This saves doing a separate RPC for Open. * For pnfs, do not do this, since the Open+LayoutGet will * be needed as a separate RPC. */ NFSLOCKMNT(nmp); if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp) && !NFSHASPNFS(nmp) && (nmp->nm_privflag & NFSMNTP_DELEGISSUED) == 0 && (!NFSMNT_RDONLY(mp) || (flags & OPENWRITE) == 0) && (flags & (ISLASTCN | ISOPEN | OPENNAMED))) == (ISLASTCN | ISOPEN)) { if ((flags & OPENREAD) != 0) openmode |= NFSV4OPEN_ACCESSREAD; if ((flags & OPENWRITE) != 0) openmode |= NFSV4OPEN_ACCESSWRITE; } NFSUNLOCKMNT(nmp); #endif newvp = NULL; NFSINCRGLOBAL(nfsstatsv1.lookupcache_misses); nanouptime(&ts); error = nfsrpc_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, td, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, openmode); if (dattrflag) (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, 0, 1); if (needs_nameddir) { vput(dvp); dvp = ap->a_dvp; } handle_error: if (error) { if (newvp != NULL) { vput(newvp); *vpp = NULL; } if (error != ENOENT) { if (NFS_ISV4(dvp)) error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); return (error); } /* The requested file was not found. */ if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && (flags & ISLASTCN)) { /* * XXX: UFS does a full VOP_ACCESS(dvp, * VWRITE) here instead of just checking * MNT_RDONLY. */ if (mp->mnt_flag & MNT_RDONLY) return (EROFS); return (EJUSTRETURN); } if ((cnp->cn_flags & MAKEENTRY) != 0 && dattrflag) { /* * Cache the modification time of the parent * directory from the post-op attributes in * the name cache entry. The negative cache * entry will be ignored once the directory * has changed. Don't bother adding the entry * if the directory has already changed. */ NFSLOCKNODE(np); if (timespeccmp(&np->n_vattr.na_mtime, &dnfsva.na_mtime, ==)) { NFSUNLOCKNODE(np); cache_enter_time(dvp, NULL, cnp, &dnfsva.na_mtime, NULL); } else NFSUNLOCKNODE(np); } return (ENOENT); } /* * Handle RENAME case... */ if (cnp->cn_nameiop == RENAME && (flags & ISLASTCN)) { if (NFS_CMPFH(np, nfhp->nfh_fh, nfhp->nfh_len)) { free(nfhp, M_NFSFH); return (EISDIR); } error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, LK_EXCLUSIVE); if (error) return (error); newvp = NFSTOV(np); /* * If n_localmodtime >= time before RPC, then * a file modification operation, such as * VOP_SETATTR() of size, has occurred while * the Lookup RPC and acquisition of the vnode * happened. As such, the attributes might * be stale, with possibly an incorrect size. */ NFSLOCKNODE(np); if (timespecisset(&np->n_localmodtime) && timespeccmp(&np->n_localmodtime, &ts, >=)) { NFSCL_DEBUG(4, "nfs_lookup: rename localmod " "stale attributes\n"); attrflag = 0; } NFSUNLOCKNODE(np); if (attrflag) (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); *vpp = newvp; return (0); } if (flags & ISDOTDOT) { ltype = NFSVOPISLOCKED(dvp); error = vfs_busy(mp, MBF_NOWAIT); if (error != 0) { vfs_ref(mp); NFSVOPUNLOCK(dvp); error = vfs_busy(mp, 0); NFSVOPLOCK(dvp, ltype | LK_RETRY); vfs_rel(mp); if (error == 0 && VN_IS_DOOMED(dvp)) { vfs_unbusy(mp); error = ENOENT; } if (error != 0) return (error); } NFSVOPUNLOCK(dvp); error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, cnp->cn_lkflags); if (error == 0) newvp = NFSTOV(np); vfs_unbusy(mp); if (newvp != dvp) NFSVOPLOCK(dvp, ltype | LK_RETRY); if (VN_IS_DOOMED(dvp)) { if (error == 0) { if (newvp == dvp) vrele(newvp); else vput(newvp); } error = ENOENT; } if (error != 0) return (error); if (attrflag) (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); } else if (NFS_CMPFH(np, nfhp->nfh_fh, nfhp->nfh_len)) { free(nfhp, M_NFSFH); - VREF(dvp); + vref(dvp); newvp = dvp; if (attrflag) (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); } else { error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, cnp->cn_lkflags); if (error) return (error); newvp = NFSTOV(np); if (opennamed) vn_irflag_set_cond(newvp, VIRF_NAMEDATTR); /* * If n_localmodtime >= time before RPC, then * a file modification operation, such as * VOP_SETATTR() of size, has occurred while * the Lookup RPC and acquisition of the vnode * happened. As such, the attributes might * be stale, with possibly an incorrect size. */ NFSLOCKNODE(np); if (timespecisset(&np->n_localmodtime) && timespeccmp(&np->n_localmodtime, &ts, >=)) { NFSCL_DEBUG(4, "nfs_lookup: localmod " "stale attributes\n"); attrflag = 0; } NFSUNLOCKNODE(np); if (attrflag) (void)nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); else if ((flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) && !(np->n_flag & NMODIFIED)) { /* * Flush the attribute cache when opening a * leaf node to ensure that fresh attributes * are fetched in nfs_open() since we did not * fetch attributes from the LOOKUP reply. */ NFSLOCKNODE(np); np->n_attrstamp = 0; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp); NFSUNLOCKNODE(np); } } if ((cnp->cn_flags & MAKEENTRY) && dvp != newvp && (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)) && attrflag != 0 && (newvp->v_type != VDIR || dattrflag != 0)) cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, newvp->v_type != VDIR ? NULL : &dnfsva.na_ctime); *vpp = newvp; return (0); } /* * nfs read call. * Just call ncl_bioread() to do the work. */ static int nfs_read(struct vop_read_args *ap) { struct vnode *vp = ap->a_vp; switch (vp->v_type) { case VREG: return (ncl_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); case VDIR: return (EISDIR); default: return (EOPNOTSUPP); } } /* * nfs readlink call */ static int nfs_readlink(struct vop_readlink_args *ap) { struct vnode *vp = ap->a_vp; if (vp->v_type != VLNK) return (EINVAL); return (ncl_bioread(vp, ap->a_uio, 0, ap->a_cred)); } /* * Do a readlink rpc. * Called by ncl_doio() from below the buffer cache. */ int ncl_readlinkrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) { int error, ret, attrflag; struct nfsvattr nfsva; error = nfsrpc_readlink(vp, uiop, cred, uiop->uio_td, &nfsva, &attrflag); if (attrflag) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (ret && !error) error = ret; } if (error && NFS_ISV4(vp)) error = nfscl_maperr(uiop->uio_td, error, (uid_t)0, (gid_t)0); return (error); } /* * nfs read rpc call * Ditto above */ int ncl_readrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) { int error, ret, attrflag; struct nfsvattr nfsva; struct nfsmount *nmp; nmp = VFSTONFS(vp->v_mount); error = EIO; attrflag = 0; if (NFSHASPNFS(nmp)) error = nfscl_doiods(vp, uiop, NULL, NULL, NFSV4OPEN_ACCESSREAD, 0, cred, uiop->uio_td); NFSCL_DEBUG(4, "readrpc: aft doiods=%d\n", error); if (error != 0 && error != EFAULT) error = nfsrpc_read(vp, uiop, cred, uiop->uio_td, &nfsva, &attrflag); if (attrflag) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (ret && !error) error = ret; } if (error && NFS_ISV4(vp)) error = nfscl_maperr(uiop->uio_td, error, (uid_t)0, (gid_t)0); return (error); } /* * nfs write call */ int ncl_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, int *iomode, int *must_commit, int called_from_strategy, int ioflag) { struct nfsvattr nfsva; int error, attrflag, ret; struct nfsmount *nmp; nmp = VFSTONFS(vp->v_mount); error = EIO; attrflag = 0; if (NFSHASPNFS(nmp)) error = nfscl_doiods(vp, uiop, iomode, must_commit, NFSV4OPEN_ACCESSWRITE, 0, cred, uiop->uio_td); NFSCL_DEBUG(4, "writerpc: aft doiods=%d\n", error); if (error != 0 && error != EFAULT) error = nfsrpc_write(vp, uiop, iomode, must_commit, cred, uiop->uio_td, &nfsva, &attrflag, called_from_strategy, ioflag); if (attrflag) { if (VTONFS(vp)->n_flag & ND_NFSV4) ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 1, 1); else ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (ret && !error) error = ret; } if (DOINGASYNC(vp)) *iomode = NFSWRITE_FILESYNC; if (error && NFS_ISV4(vp)) error = nfscl_maperr(uiop->uio_td, error, (uid_t)0, (gid_t)0); return (error); } /* * nfs mknod rpc * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the * mode set to specify the file type and the size field for rdev. */ static int nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap) { struct nfsvattr nfsva, dnfsva; struct vnode *newvp = NULL; struct nfsnode *np = NULL, *dnp; struct nfsfh *nfhp; struct vattr vattr; int error = 0, attrflag, dattrflag; u_int32_t rdev; if (VATTR_ISDEV(vap)) rdev = vap->va_rdev; else if (vap->va_type == VFIFO || vap->va_type == VSOCK) rdev = 0xffffffff; else return (EOPNOTSUPP); if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) return (error); error = nfsrpc_mknod(dvp, cnp->cn_nameptr, cnp->cn_namelen, vap, rdev, vap->va_type, cnp->cn_cred, curthread, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag); if (!error) { if (!nfhp) (void) nfsrpc_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, curthread, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, 0); if (nfhp) error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, curthread, &np, LK_EXCLUSIVE); } if (dattrflag) (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, 0, 1); if (!error) { newvp = NFSTOV(np); if (attrflag != 0) { error = nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); if (error != 0) vput(newvp); } } if (!error) { *vpp = newvp; } else if (NFS_ISV4(dvp)) { error = nfscl_maperr(curthread, error, vap->va_uid, vap->va_gid); } dnp = VTONFS(dvp); NFSLOCKNODE(dnp); dnp->n_flag |= NMODIFIED; if (!dattrflag) { dnp->n_attrstamp = 0; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); } NFSUNLOCKNODE(dnp); return (error); } /* * nfs mknod vop * just call nfs_mknodrpc() to do the work. */ /* ARGSUSED */ static int nfs_mknod(struct vop_mknod_args *ap) { return (nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap)); } static struct mtx nfs_cverf_mtx; MTX_SYSINIT(nfs_cverf_mtx, &nfs_cverf_mtx, "NFS create verifier mutex", MTX_DEF); static nfsquad_t nfs_get_cverf(void) { static nfsquad_t cverf; nfsquad_t ret; static int cverf_initialized = 0; mtx_lock(&nfs_cverf_mtx); if (cverf_initialized == 0) { cverf.lval[0] = arc4random(); cverf.lval[1] = arc4random(); cverf_initialized = 1; } else cverf.qval++; ret = cverf; mtx_unlock(&nfs_cverf_mtx); return (ret); } /* * nfs file create call */ static int nfs_create(struct vop_create_args *ap) { struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct componentname *cnp = ap->a_cnp; struct nfsnode *np = NULL, *dnp; struct vnode *newvp = NULL; struct nfsmount *nmp; struct nfsvattr dnfsva, nfsva; struct nfsfh *nfhp; nfsquad_t cverf; int error = 0, attrflag, dattrflag, fmode = 0; struct vattr vattr; bool is_nameddir, needs_nameddir, opennamed; /* * Oops, not for me.. */ if (vap->va_type == VSOCK) return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap)); if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) return (error); if (vap->va_vaflags & VA_EXCLUSIVE) fmode |= O_EXCL; dnp = VTONFS(dvp); nmp = VFSTONFS(dvp->v_mount); needs_nameddir = false; if (NFSHASNFSV4(nmp) && NFSHASNFSV4N(nmp)) { opennamed = (cnp->cn_flags & (OPENNAMED | ISLASTCN)) == (OPENNAMED | ISLASTCN); is_nameddir = (vn_irflag_read(dvp) & VIRF_NAMEDDIR) != 0; if (opennamed || is_nameddir) { cnp->cn_flags &= ~MAKEENTRY; if (!is_nameddir) needs_nameddir = true; } } /* * If the named attribute directory is needed, acquire it now. */ if (needs_nameddir) { KASSERT(dnp->n_v4 == NULL, ("nfs_create: O_NAMEDATTR when" " n_v4 not NULL")); error = nfs_get_namedattrdir(dvp, cnp, &newvp); if (error != 0) return (error); dvp = newvp; dnp = VTONFS(dvp); newvp = NULL; } again: /* For NFSv4, wait until any remove is done. */ NFSLOCKNODE(dnp); while (NFSHASNFSV4(nmp) && (dnp->n_flag & NREMOVEINPROG)) { dnp->n_flag |= NREMOVEWANT; (void) msleep((caddr_t)dnp, &dnp->n_mtx, PZERO, "nfscrt", 0); } NFSUNLOCKNODE(dnp); cverf = nfs_get_cverf(); error = nfsrpc_create(dvp, cnp->cn_nameptr, cnp->cn_namelen, vap, cverf, fmode, cnp->cn_cred, curthread, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag); if (!error) { if (nfhp == NULL) (void) nfsrpc_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, curthread, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, 0); if (nfhp != NULL) error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, curthread, &np, LK_EXCLUSIVE); } if (dattrflag) (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, 0, 1); if (!error) { newvp = NFSTOV(np); if (attrflag == 0) error = nfsrpc_getattr(newvp, cnp->cn_cred, curthread, &nfsva); if (error == 0) error = nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); } if (error) { if (newvp != NULL) { vput(newvp); newvp = NULL; } if (NFS_ISV34(dvp) && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) { fmode &= ~O_EXCL; goto again; } } else if (NFS_ISV34(dvp) && (fmode & O_EXCL)) { if (nfscl_checksattr(vap, &nfsva)) { error = nfsrpc_setattr(newvp, vap, NULL, cnp->cn_cred, curthread, &nfsva, &attrflag); if (error && (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL)) { /* try again without setting uid/gid */ vap->va_uid = (uid_t)VNOVAL; vap->va_gid = (uid_t)VNOVAL; error = nfsrpc_setattr(newvp, vap, NULL, cnp->cn_cred, curthread, &nfsva, &attrflag); } if (attrflag) (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); if (error != 0) vput(newvp); } } if (!error) { if ((cnp->cn_flags & MAKEENTRY) && attrflag) { if (dvp != newvp) cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, NULL); else printf("nfs_create: bogus NFS server returned " "the directory as the new file object\n"); } *ap->a_vpp = newvp; } else if (NFS_ISV4(dvp)) { error = nfscl_maperr(curthread, error, vap->va_uid, vap->va_gid); } NFSLOCKNODE(dnp); dnp->n_flag |= NMODIFIED; if (!dattrflag) { dnp->n_attrstamp = 0; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); } NFSUNLOCKNODE(dnp); if (needs_nameddir) vput(dvp); return (error); } /* * nfs file remove call * To try and make nfs semantics closer to ufs semantics, a file that has * other processes using the vnode is renamed instead of removed and then * removed later on the last close. * - If v_usecount > 1 * If a rename is not already in the works * call nfs_sillyrename() to set it up * else * do the remove rpc */ static int nfs_remove(struct vop_remove_args *ap) { struct vnode *vp = ap->a_vp; struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; struct nfsnode *np = VTONFS(vp); int error = 0; struct vattr vattr; struct nfsmount *nmp; KASSERT(vrefcnt(vp) > 0, ("nfs_remove: bad v_usecount")); if (vp->v_type == VDIR) error = EPERM; else if (vrefcnt(vp) == 1 || (np->n_sillyrename && VOP_GETATTR(vp, &vattr, cnp->cn_cred) == 0 && vattr.va_nlink > 1)) { nmp = VFSTONFS(vp->v_mount); /* * Purge the name cache so that the chance of a lookup for * the name succeeding while the remove is in progress is * minimized. Without node locking it can still happen, such * that an I/O op returns ESTALE, but since you get this if * another host removes the file.. */ cache_purge(vp); /* * throw away biocache buffers, mainly to avoid * unnecessary delayed writes later. * Flushing here would be more correct for the case * where nfs_close() did not do a flush. However, it * could be a large performance hit for some servers * and only matters when the file name being removed is * one of multiple hard links. */ if (!NFSHASNFSV4(nmp) || !NFSHASNFSV4N(nmp) || (nmp->nm_flag & NFSMNT_NOCTO) == 0) error = ncl_vinvalbuf(vp, 0, curthread, 1); if (error != EINTR && error != EIO) /* Do the rpc */ error = nfs_removerpc(dvp, vp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, curthread, false); /* * Kludge City: If the first reply to the remove rpc is lost.. * the reply to the retransmitted request will be ENOENT * since the file was in fact removed * Therefore, we cheat and return success. */ if (error == ENOENT) error = 0; } else if (!np->n_sillyrename) error = nfs_sillyrename(dvp, vp, cnp); NFSLOCKNODE(np); np->n_attrstamp = 0; NFSUNLOCKNODE(np); KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); return (error); } /* * nfs file remove rpc called from nfs_inactive */ int ncl_removeit(struct sillyrename *sp, struct vnode *vp) { /* * Make sure that the directory vnode is still valid. * XXX we should lock sp->s_dvp here. */ if (sp->s_dvp->v_type == VBAD) return (0); return (nfs_removerpc(sp->s_dvp, vp, sp->s_name, sp->s_namlen, sp->s_cred, NULL, true)); } /* * Handle the nfsremove_status reply from the RPC function. */ static void nfs_removestatus(struct vnode *vp, nfsremove_status file_status, bool silly, struct thread *td) { switch (file_status) { case NLINK_ZERO: /* Get rid of any delegation. */ nfscl_delegreturnvp(vp, false, td); /* FALLTHROUGH */ case DELETED: /* Throw away buffer cache blocks. */ (void)ncl_vinvalbuf(vp, 0, td, 1); break; case VALID: /* Nothing to do, delegation is still ok. */ break; default: break; } } /* * Nfs remove rpc, called from nfs_remove() and ncl_removeit(). */ static int nfs_removerpc(struct vnode *dvp, struct vnode *vp, char *name, int namelen, struct ucred *cred, struct thread *td, bool silly) { struct nfsvattr dnfsva, nfsva; struct nfsnode *dnp = VTONFS(dvp); struct nfsmount *nmp; int attrflag, error = 0, dattrflag; nfsremove_status file_status; nmp = VFSTONFS(dvp->v_mount); NFSLOCKNODE(dnp); dnp->n_flag |= NREMOVEINPROG; NFSUNLOCKNODE(dnp); error = nfsrpc_remove(dvp, name, namelen, vp, &nfsva, &attrflag, &file_status, &dnfsva, &dattrflag, cred, td); NFSLOCKNODE(dnp); if ((dnp->n_flag & NREMOVEWANT)) { dnp->n_flag &= ~(NREMOVEWANT | NREMOVEINPROG); NFSUNLOCKNODE(dnp); wakeup((caddr_t)dnp); } else { dnp->n_flag &= ~NREMOVEINPROG; NFSUNLOCKNODE(dnp); } if (NFSHASNFSV4(nmp) && NFSHASNFSV4N(nmp)) { if (file_status != DELETED && attrflag != 0) (void)nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if ((nmp->nm_flag & NFSMNT_NOCTO) != 0) nfs_removestatus(vp, file_status, silly, td); } if (dattrflag != 0) (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, 0, 1); NFSLOCKNODE(dnp); dnp->n_flag |= NMODIFIED; if (dattrflag == 0) { dnp->n_attrstamp = 0; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); } NFSUNLOCKNODE(dnp); if (error && NFS_ISV4(dvp)) error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); return (error); } /* * nfs file rename call */ static int nfs_rename(struct vop_rename_args *ap) { struct vnode *fvp = ap->a_fvp; struct vnode *tvp = ap->a_tvp; struct vnode *fdvp = ap->a_fdvp; struct vnode *tdvp = ap->a_tdvp; struct componentname *tcnp = ap->a_tcnp; struct componentname *fcnp = ap->a_fcnp; struct nfsnode *fnp = VTONFS(ap->a_fvp); struct nfsnode *tdnp = VTONFS(ap->a_tdvp); struct nfsv4node *newv4 = NULL; struct nfsmount *nmp; int error; /* Check for cross-device rename */ if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { error = EXDEV; goto out; } nmp = VFSTONFS(fvp->v_mount); if (fvp == tvp) { printf("nfs_rename: fvp == tvp (can't happen)\n"); error = 0; goto out; } if ((error = NFSVOPLOCK(fvp, LK_EXCLUSIVE)) != 0) goto out; /* * We have to flush B_DELWRI data prior to renaming * the file. If we don't, the delayed-write buffers * can be flushed out later after the file has gone stale * under NFSV3. NFSV2 does not have this problem because * ( as far as I can tell ) it flushes dirty buffers more * often. * * Skip the rename operation if the fsync fails, this can happen * due to the server's volume being full, when we pushed out data * that was written back to our cache earlier. Not checking for * this condition can result in potential (silent) data loss. */ if ((nmp->nm_flag & NFSMNT_NOCTO) == 0 || !NFSHASNFSV4(nmp) || !NFSHASNFSV4N(nmp) || nfscl_mustflush(fvp) != 0) error = VOP_FSYNC(fvp, MNT_WAIT, curthread); NFSVOPUNLOCK(fvp); if (error == 0 && tvp != NULL && ((nmp->nm_flag & NFSMNT_NOCTO) == 0 || !NFSHASNFSV4(nmp) || !NFSHASNFSV4N(nmp) || nfscl_mustflush(tvp) != 0)) error = VOP_FSYNC(tvp, MNT_WAIT, curthread); if (error != 0) goto out; /* * If the tvp exists and is in use, sillyrename it before doing the * rename of the new file over it. * XXX Can't sillyrename a directory. */ if (tvp && vrefcnt(tvp) > 1 && !VTONFS(tvp)->n_sillyrename && tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) { vput(tvp); tvp = NULL; } error = nfs_renamerpc(fdvp, fvp, fcnp->cn_nameptr, fcnp->cn_namelen, tdvp, tvp, tcnp->cn_nameptr, tcnp->cn_namelen, false, tcnp->cn_cred, curthread); if (error == 0 && NFS_ISV4(tdvp)) { /* * For NFSv4, check to see if it is the same name and * replace the name, if it is different. */ newv4 = malloc( sizeof (struct nfsv4node) + tdnp->n_fhp->nfh_len + tcnp->cn_namelen - 1, M_NFSV4NODE, M_WAITOK); NFSLOCKNODE(tdnp); NFSLOCKNODE(fnp); if (fnp->n_v4 != NULL && fvp->v_type == VREG && (fnp->n_v4->n4_namelen != tcnp->cn_namelen || NFSBCMP(tcnp->cn_nameptr, NFS4NODENAME(fnp->n_v4), tcnp->cn_namelen) || tdnp->n_fhp->nfh_len != fnp->n_v4->n4_fhlen || NFSBCMP(tdnp->n_fhp->nfh_fh, fnp->n_v4->n4_data, tdnp->n_fhp->nfh_len))) { free(fnp->n_v4, M_NFSV4NODE); fnp->n_v4 = newv4; newv4 = NULL; fnp->n_v4->n4_fhlen = tdnp->n_fhp->nfh_len; fnp->n_v4->n4_namelen = tcnp->cn_namelen; NFSBCOPY(tdnp->n_fhp->nfh_fh, fnp->n_v4->n4_data, tdnp->n_fhp->nfh_len); NFSBCOPY(tcnp->cn_nameptr, NFS4NODENAME(fnp->n_v4), tcnp->cn_namelen); } NFSUNLOCKNODE(tdnp); NFSUNLOCKNODE(fnp); if (newv4 != NULL) free(newv4, M_NFSV4NODE); } if (fvp->v_type == VDIR) { if (tvp != NULL && tvp->v_type == VDIR) cache_purge(tdvp); cache_purge(fdvp); } out: if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp) vput(tvp); vrele(fdvp); vrele(fvp); /* * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. */ if (error == ENOENT) error = 0; return (error); } /* * nfs file rename rpc called from nfs_remove() above */ static int nfs_renameit(struct vnode *sdvp, struct vnode *svp, struct componentname *scnp, struct sillyrename *sp) { return (nfs_renamerpc(sdvp, svp, scnp->cn_nameptr, scnp->cn_namelen, sdvp, NULL, sp->s_name, sp->s_namlen, true, scnp->cn_cred, curthread)); } /* * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit(). */ static int nfs_renamerpc(struct vnode *fdvp, struct vnode *fvp, char *fnameptr, int fnamelen, struct vnode *tdvp, struct vnode *tvp, char *tnameptr, int tnamelen, bool silly, struct ucred *cred, struct thread *td) { struct nfsvattr fnfsva, tnfsva, tvpnfsva; struct nfsnode *fdnp = VTONFS(fdvp); struct nfsnode *tdnp = VTONFS(tdvp); struct nfsmount *nmp; int error = 0, fattrflag, tattrflag, tvpattrflag; nfsremove_status tvp_status; nmp = VFSTONFS(fdvp->v_mount); error = nfsrpc_rename(fdvp, fvp, fnameptr, fnamelen, tdvp, tvp, tnameptr, tnamelen, &tvp_status, &fnfsva, &tnfsva, &fattrflag, &tattrflag, &tvpnfsva, &tvpattrflag, cred, td); NFSLOCKNODE(fdnp); fdnp->n_flag |= NMODIFIED; if (fattrflag != 0) { NFSUNLOCKNODE(fdnp); (void) nfscl_loadattrcache(&fdvp, &fnfsva, NULL, 0, 1); } else { fdnp->n_attrstamp = 0; NFSUNLOCKNODE(fdnp); KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(fdvp); } NFSLOCKNODE(tdnp); tdnp->n_flag |= NMODIFIED; if (tattrflag != 0) { NFSUNLOCKNODE(tdnp); (void) nfscl_loadattrcache(&tdvp, &tnfsva, NULL, 0, 1); } else { tdnp->n_attrstamp = 0; NFSUNLOCKNODE(tdnp); KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(tdvp); } if (tvp != NULL) { if (NFSHASNFSV4(nmp) && NFSHASNFSV4N(nmp) && (nmp->nm_flag & NFSMNT_NOCTO) != 0) nfs_removestatus(tvp, tvp_status, silly, td); if (!silly && tvpattrflag != 0) (void)nfscl_loadattrcache(&tvp, &tvpnfsva, NULL, 0, 1); } if (error && NFS_ISV4(fdvp)) error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); return (error); } /* * nfs hard link create call */ static int nfs_link(struct vop_link_args *ap) { struct vnode *vp = ap->a_vp; struct vnode *tdvp = ap->a_tdvp; struct componentname *cnp = ap->a_cnp; struct nfsnode *np, *tdnp; struct nfsvattr nfsva, dnfsva; int error = 0, attrflag, dattrflag; /* * Push all writes to the server, so that the attribute cache * doesn't get "out of sync" with the server. * XXX There should be a better way! */ #ifdef notnow VOP_FSYNC(vp, MNT_WAIT, curthread); #endif error = nfsrpc_link(tdvp, vp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, curthread, &dnfsva, &nfsva, &attrflag, &dattrflag); tdnp = VTONFS(tdvp); NFSLOCKNODE(tdnp); tdnp->n_flag |= NMODIFIED; if (dattrflag != 0) { NFSUNLOCKNODE(tdnp); (void) nfscl_loadattrcache(&tdvp, &dnfsva, NULL, 0, 1); } else { tdnp->n_attrstamp = 0; NFSUNLOCKNODE(tdnp); KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(tdvp); } if (attrflag) (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); else { np = VTONFS(vp); NFSLOCKNODE(np); np->n_attrstamp = 0; NFSUNLOCKNODE(np); KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); } /* * If negative lookup caching is enabled, I might as well * add an entry for this node. Not necessary for correctness, * but if negative caching is enabled, then the system * must care about lookup caching hit rate, so... */ if (VFSTONFS(vp->v_mount)->nm_negnametimeo != 0 && (cnp->cn_flags & MAKEENTRY) && attrflag != 0 && error == 0) { if (tdvp != vp) cache_enter_time(tdvp, vp, cnp, &nfsva.na_ctime, NULL); else printf("nfs_link: bogus NFS server returned " "the directory as the new link\n"); } if (error && NFS_ISV4(vp)) error = nfscl_maperr(curthread, error, (uid_t)0, (gid_t)0); return (error); } /* * nfs symbolic link create call */ static int nfs_symlink(struct vop_symlink_args *ap) { struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct componentname *cnp = ap->a_cnp; struct nfsvattr nfsva, dnfsva; struct nfsfh *nfhp; struct nfsnode *np = NULL, *dnp; struct vnode *newvp = NULL; int error = 0, attrflag, dattrflag, ret; vap->va_type = VLNK; error = nfsrpc_symlink(dvp, cnp->cn_nameptr, cnp->cn_namelen, ap->a_target, vap, cnp->cn_cred, curthread, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag); if (nfhp) { ret = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, curthread, &np, LK_EXCLUSIVE); if (!ret) newvp = NFSTOV(np); else if (!error) error = ret; } if (newvp != NULL) { if (attrflag) (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); } else if (!error) { /* * If we do not have an error and we could not extract the * newvp from the response due to the request being NFSv2, we * have to do a lookup in order to obtain a newvp to return. */ error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, curthread, &np); if (!error) newvp = NFSTOV(np); } if (error) { if (newvp) vput(newvp); if (NFS_ISV4(dvp)) error = nfscl_maperr(curthread, error, vap->va_uid, vap->va_gid); } else { *ap->a_vpp = newvp; } dnp = VTONFS(dvp); NFSLOCKNODE(dnp); dnp->n_flag |= NMODIFIED; if (dattrflag != 0) { NFSUNLOCKNODE(dnp); (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, 0, 1); } else { dnp->n_attrstamp = 0; NFSUNLOCKNODE(dnp); KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); } /* * If negative lookup caching is enabled, I might as well * add an entry for this node. Not necessary for correctness, * but if negative caching is enabled, then the system * must care about lookup caching hit rate, so... */ if (VFSTONFS(dvp->v_mount)->nm_negnametimeo != 0 && (cnp->cn_flags & MAKEENTRY) && attrflag != 0 && error == 0) { if (dvp != newvp) cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, NULL); else printf("nfs_symlink: bogus NFS server returned " "the directory as the new file object\n"); } return (error); } /* * nfs make dir call */ static int nfs_mkdir(struct vop_mkdir_args *ap) { struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct componentname *cnp = ap->a_cnp; struct nfsnode *np = NULL, *dnp; struct vnode *newvp = NULL; struct vattr vattr; struct nfsfh *nfhp; struct nfsvattr nfsva, dnfsva; int error = 0, attrflag, dattrflag, ret; if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred)) != 0) return (error); vap->va_type = VDIR; error = nfsrpc_mkdir(dvp, cnp->cn_nameptr, cnp->cn_namelen, vap, cnp->cn_cred, curthread, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag); dnp = VTONFS(dvp); NFSLOCKNODE(dnp); dnp->n_flag |= NMODIFIED; if (dattrflag != 0) { NFSUNLOCKNODE(dnp); (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, 0, 1); } else { dnp->n_attrstamp = 0; NFSUNLOCKNODE(dnp); KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); } if (nfhp) { ret = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, curthread, &np, LK_EXCLUSIVE); if (!ret) { newvp = NFSTOV(np); if (attrflag) (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); } else if (!error) error = ret; } if (!error && newvp == NULL) { error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, curthread, &np); if (!error) { newvp = NFSTOV(np); if (newvp->v_type != VDIR) error = EEXIST; } } if (error) { if (newvp) vput(newvp); if (NFS_ISV4(dvp)) error = nfscl_maperr(curthread, error, vap->va_uid, vap->va_gid); } else { /* * If negative lookup caching is enabled, I might as well * add an entry for this node. Not necessary for correctness, * but if negative caching is enabled, then the system * must care about lookup caching hit rate, so... */ if (VFSTONFS(dvp->v_mount)->nm_negnametimeo != 0 && (cnp->cn_flags & MAKEENTRY) && attrflag != 0 && dattrflag != 0) { if (dvp != newvp) cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, &dnfsva.na_ctime); else printf("nfs_mkdir: bogus NFS server returned " "the directory that the directory was " "created in as the new file object\n"); } *ap->a_vpp = newvp; } return (error); } /* * nfs remove directory call */ static int nfs_rmdir(struct vop_rmdir_args *ap) { struct vnode *vp = ap->a_vp; struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; struct nfsnode *dnp; struct nfsvattr dnfsva; int error, dattrflag; if (dvp == vp) return (EINVAL); error = nfsrpc_rmdir(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, curthread, &dnfsva, &dattrflag); dnp = VTONFS(dvp); NFSLOCKNODE(dnp); dnp->n_flag |= NMODIFIED; if (dattrflag != 0) { NFSUNLOCKNODE(dnp); (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, 0, 1); } else { dnp->n_attrstamp = 0; NFSUNLOCKNODE(dnp); KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); } cache_purge(dvp); cache_purge(vp); if (error && NFS_ISV4(dvp)) error = nfscl_maperr(curthread, error, (uid_t)0, (gid_t)0); /* * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. */ if (error == ENOENT) error = 0; return (error); } /* * nfs readdir call */ static int nfs_readdir(struct vop_readdir_args *ap) { struct vnode *vp = ap->a_vp; struct nfsnode *np = VTONFS(vp); struct uio *uio = ap->a_uio; ssize_t tresid, left; int error = 0; struct vattr vattr; if (ap->a_eofflag != NULL) *ap->a_eofflag = 0; if (vp->v_type != VDIR) return(EPERM); /* * First, check for hit on the EOF offset cache */ NFSLOCKNODE(np); if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset && (np->n_flag & NMODIFIED) == 0) { NFSUNLOCKNODE(np); if (VOP_GETATTR(vp, &vattr, ap->a_cred) == 0) { NFSLOCKNODE(np); if ((NFS_ISV4(vp) && np->n_change == vattr.va_filerev) || !NFS_TIMESPEC_COMPARE(&np->n_mtime, &vattr.va_mtime)) { NFSUNLOCKNODE(np); NFSINCRGLOBAL(nfsstatsv1.direofcache_hits); if (ap->a_eofflag != NULL) *ap->a_eofflag = 1; return (0); } else NFSUNLOCKNODE(np); } } else NFSUNLOCKNODE(np); /* * NFS always guarantees that directory entries don't straddle * DIRBLKSIZ boundaries. As such, we need to limit the size * to an exact multiple of DIRBLKSIZ, to avoid copying a partial * directory entry. */ left = uio->uio_resid % DIRBLKSIZ; if (left == uio->uio_resid) return (EINVAL); uio->uio_resid -= left; /* * For readdirplus, if starting to read the directory, * purge the name cache, since it will be reloaded by * this directory read. * This removes potentially stale name cache entries. */ if (uio->uio_offset == 0 && (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRPLUS) != 0) cache_purge(vp); /* * Call ncl_bioread() to do the real work. */ tresid = uio->uio_resid; error = ncl_bioread(vp, uio, 0, ap->a_cred); if (!error && uio->uio_resid == tresid) { NFSINCRGLOBAL(nfsstatsv1.direofcache_misses); if (ap->a_eofflag != NULL) *ap->a_eofflag = 1; } /* Add the partial DIRBLKSIZ (left) back in. */ uio->uio_resid += left; return (error); } /* * Readdir rpc call. * Called from below the buffer cache by ncl_doio(). */ int ncl_readdirrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, struct thread *td) { struct nfsvattr nfsva; nfsuint64 *cookiep, cookie; struct nfsnode *dnp = VTONFS(vp); struct nfsmount *nmp = VFSTONFS(vp->v_mount); int error = 0, eof, attrflag; KASSERT(uiop->uio_iovcnt == 1 && (uiop->uio_offset & (DIRBLKSIZ - 1)) == 0 && (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, ("nfs readdirrpc bad uio")); /* * If there is no cookie, assume directory was stale. */ ncl_dircookie_lock(dnp); NFSUNLOCKNODE(dnp); cookiep = ncl_getcookie(dnp, uiop->uio_offset, 0); if (cookiep) { cookie = *cookiep; ncl_dircookie_unlock(dnp); } else { ncl_dircookie_unlock(dnp); return (NFSERR_BAD_COOKIE); } if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) (void)ncl_fsinfo(nmp, vp, cred, td); error = nfsrpc_readdir(vp, uiop, &cookie, cred, td, &nfsva, &attrflag, &eof); if (attrflag) (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (!error) { /* * We are now either at the end of the directory or have filled * the block. */ if (eof) { NFSLOCKNODE(dnp); dnp->n_direofoffset = uiop->uio_offset; NFSUNLOCKNODE(dnp); } else { if (uiop->uio_resid > 0) printf("EEK! readdirrpc resid > 0\n"); ncl_dircookie_lock(dnp); NFSUNLOCKNODE(dnp); cookiep = ncl_getcookie(dnp, uiop->uio_offset, 1); *cookiep = cookie; ncl_dircookie_unlock(dnp); } } else if (NFS_ISV4(vp)) { error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); } return (error); } /* * NFS V3 readdir plus RPC. Used in place of ncl_readdirrpc(). */ int ncl_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, struct thread *td) { struct nfsvattr nfsva; nfsuint64 *cookiep, cookie; struct nfsnode *dnp = VTONFS(vp); struct nfsmount *nmp = VFSTONFS(vp->v_mount); int error = 0, attrflag, eof; KASSERT(uiop->uio_iovcnt == 1 && (uiop->uio_offset & (DIRBLKSIZ - 1)) == 0 && (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, ("nfs readdirplusrpc bad uio")); /* * If there is no cookie, assume directory was stale. */ ncl_dircookie_lock(dnp); NFSUNLOCKNODE(dnp); cookiep = ncl_getcookie(dnp, uiop->uio_offset, 0); if (cookiep) { cookie = *cookiep; ncl_dircookie_unlock(dnp); } else { ncl_dircookie_unlock(dnp); return (NFSERR_BAD_COOKIE); } if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) (void)ncl_fsinfo(nmp, vp, cred, td); error = nfsrpc_readdirplus(vp, uiop, &cookie, cred, td, &nfsva, &attrflag, &eof); if (attrflag) (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (!error) { /* * We are now either at end of the directory or have filled the * the block. */ if (eof) { NFSLOCKNODE(dnp); dnp->n_direofoffset = uiop->uio_offset; NFSUNLOCKNODE(dnp); } else { if (uiop->uio_resid > 0) printf("EEK! readdirplusrpc resid > 0\n"); ncl_dircookie_lock(dnp); NFSUNLOCKNODE(dnp); cookiep = ncl_getcookie(dnp, uiop->uio_offset, 1); *cookiep = cookie; ncl_dircookie_unlock(dnp); } } else if (NFS_ISV4(vp)) { error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); } return (error); } /* * Silly rename. To make the NFS filesystem that is stateless look a little * more like the "ufs" a remove of an active vnode is translated to a rename * to a funny looking filename that is removed by nfs_inactive on the * nfsnode. There is the potential for another process on a different client * to create the same funny name between the nfs_lookitup() fails and the * nfs_rename() completes, but... */ static int nfs_sillyrename(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) { struct sillyrename *sp; struct nfsnode *np; int error; short pid; unsigned int lticks; cache_purge(dvp); np = VTONFS(vp); KASSERT(vp->v_type != VDIR, ("nfs: sillyrename dir")); sp = malloc(sizeof (struct sillyrename), M_NEWNFSREQ, M_WAITOK); sp->s_cred = crhold(cnp->cn_cred); sp->s_dvp = dvp; - VREF(dvp); + vref(dvp); /* * Fudge together a funny name. * Changing the format of the funny name to accommodate more * sillynames per directory. * The name is now changed to .nfs...4, where ticks is * CPU ticks since boot. */ pid = curthread->td_proc->p_pid; lticks = (unsigned int)ticks; for ( ; ; ) { sp->s_namlen = sprintf(sp->s_name, ".nfs.%08x.%04x4.4", lticks, pid); if (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, curthread, NULL)) break; lticks++; } error = nfs_renameit(dvp, vp, cnp, sp); if (error) goto bad; error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, curthread, &np); np->n_sillyrename = sp; return (0); bad: vrele(sp->s_dvp); crfree(sp->s_cred); free(sp, M_NEWNFSREQ); return (error); } /* * Look up a file name and optionally either update the file handle or * allocate an nfsnode, depending on the value of npp. * npp == NULL --> just do the lookup * *npp == NULL --> allocate a new nfsnode and make sure attributes are * handled too * *npp != NULL --> update the file handle in the vnode */ static int nfs_lookitup(struct vnode *dvp, char *name, int len, struct ucred *cred, struct thread *td, struct nfsnode **npp) { struct vnode *newvp = NULL, *vp; struct nfsnode *np, *dnp = VTONFS(dvp); struct nfsfh *nfhp, *onfhp; struct nfsvattr nfsva, dnfsva; struct componentname cn; int error = 0, attrflag, dattrflag; u_int hash; struct timespec ts; nanouptime(&ts); error = nfsrpc_lookup(dvp, name, len, cred, td, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, 0); if (dattrflag) (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, 0, 1); if (npp && !error) { if (*npp != NULL) { np = *npp; vp = NFSTOV(np); /* * For NFSv4, check to see if it is the same name and * replace the name, if it is different. */ if (np->n_v4 != NULL && nfsva.na_type == VREG && (np->n_v4->n4_namelen != len || NFSBCMP(name, NFS4NODENAME(np->n_v4), len) || dnp->n_fhp->nfh_len != np->n_v4->n4_fhlen || NFSBCMP(dnp->n_fhp->nfh_fh, np->n_v4->n4_data, dnp->n_fhp->nfh_len))) { free(np->n_v4, M_NFSV4NODE); np->n_v4 = malloc( sizeof (struct nfsv4node) + dnp->n_fhp->nfh_len + len - 1, M_NFSV4NODE, M_WAITOK); np->n_v4->n4_fhlen = dnp->n_fhp->nfh_len; np->n_v4->n4_namelen = len; NFSBCOPY(dnp->n_fhp->nfh_fh, np->n_v4->n4_data, dnp->n_fhp->nfh_len); NFSBCOPY(name, NFS4NODENAME(np->n_v4), len); } hash = fnv_32_buf(nfhp->nfh_fh, nfhp->nfh_len, FNV1_32_INIT); onfhp = np->n_fhp; /* * Rehash node for new file handle. */ vfs_hash_rehash(vp, hash); np->n_fhp = nfhp; if (onfhp != NULL) free(onfhp, M_NFSFH); newvp = NFSTOV(np); } else if (NFS_CMPFH(dnp, nfhp->nfh_fh, nfhp->nfh_len)) { free(nfhp, M_NFSFH); - VREF(dvp); + vref(dvp); newvp = dvp; } else { cn.cn_nameptr = name; cn.cn_namelen = len; error = nfscl_nget(dvp->v_mount, dvp, nfhp, &cn, td, &np, LK_EXCLUSIVE); if (error) return (error); newvp = NFSTOV(np); /* * If n_localmodtime >= time before RPC, then * a file modification operation, such as * VOP_SETATTR() of size, has occurred while * the Lookup RPC and acquisition of the vnode * happened. As such, the attributes might * be stale, with possibly an incorrect size. */ NFSLOCKNODE(np); if (timespecisset(&np->n_localmodtime) && timespeccmp(&np->n_localmodtime, &ts, >=)) { NFSCL_DEBUG(4, "nfs_lookitup: localmod " "stale attributes\n"); attrflag = 0; } NFSUNLOCKNODE(np); } if (!attrflag && *npp == NULL) { if (newvp == dvp) vrele(newvp); else vput(newvp); return (ENOENT); } if (attrflag) (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 0, 1); } if (npp && *npp == NULL) { if (error) { if (newvp) { if (newvp == dvp) vrele(newvp); else vput(newvp); } } else *npp = np; } if (error && NFS_ISV4(dvp)) error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); return (error); } /* * Nfs Version 3 and 4 commit rpc */ int ncl_commit(struct vnode *vp, u_quad_t offset, int cnt, struct ucred *cred, struct thread *td) { struct nfsvattr nfsva; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *np; struct uio uio; int error, attrflag; np = VTONFS(vp); error = EIO; attrflag = 0; if (NFSHASPNFS(nmp) && (np->n_flag & NDSCOMMIT) != 0) { uio.uio_offset = offset; uio.uio_resid = cnt; error = nfscl_doiods(vp, &uio, NULL, NULL, NFSV4OPEN_ACCESSWRITE, 1, cred, td); if (error != 0) { NFSLOCKNODE(np); np->n_flag &= ~NDSCOMMIT; NFSUNLOCKNODE(np); } } if (error != 0) { mtx_lock(&nmp->nm_mtx); if ((nmp->nm_state & NFSSTA_HASWRITEVERF) == 0) { mtx_unlock(&nmp->nm_mtx); return (0); } mtx_unlock(&nmp->nm_mtx); error = nfsrpc_commit(vp, offset, cnt, cred, td, &nfsva, &attrflag); } if (attrflag != 0) (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error != 0 && NFS_ISV4(vp)) error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); return (error); } /* * Strategy routine. * For async requests when nfsiod(s) are running, queue the request by * calling ncl_asyncio(), otherwise just all ncl_doio() to do the * request. */ static int nfs_strategy(struct vop_strategy_args *ap) { struct buf *bp; struct vnode *vp; struct ucred *cr; bp = ap->a_bp; vp = ap->a_vp; KASSERT(bp->b_vp == vp, ("missing b_getvp")); KASSERT(!(bp->b_flags & B_DONE), ("nfs_strategy: buffer %p unexpectedly marked B_DONE", bp)); if (vp->v_type == VREG && bp->b_blkno == bp->b_lblkno) bp->b_blkno = bp->b_lblkno * (vp->v_bufobj.bo_bsize / DEV_BSIZE); if (bp->b_iocmd == BIO_READ) cr = bp->b_rcred; else cr = bp->b_wcred; /* * If the op is asynchronous and an i/o daemon is waiting * queue the request, wake it up and wait for completion * otherwise just do it ourselves. */ if ((bp->b_flags & B_ASYNC) == 0 || ncl_asyncio(VFSTONFS(vp->v_mount), bp, NOCRED, curthread)) (void) ncl_doio(vp, bp, cr, curthread, 1); return (0); } /* * fsync vnode op. Just call ncl_flush() with commit == 1. */ /* ARGSUSED */ static int nfs_fsync(struct vop_fsync_args *ap) { if (ap->a_vp->v_type != VREG) { /* * For NFS, metadata is changed synchronously on the server, * so there is nothing to flush. Also, ncl_flush() clears * the NMODIFIED flag and that shouldn't be done here for * directories. */ return (0); } return (ncl_flush(ap->a_vp, ap->a_waitfor, ap->a_td, 1, 0)); } /* * Flush all the blocks associated with a vnode. * Walk through the buffer pool and push any dirty pages * associated with the vnode. * If the called_from_renewthread argument is TRUE, it has been called * from the NFSv4 renew thread and, as such, cannot block indefinitely * waiting for a buffer write to complete. */ int ncl_flush(struct vnode *vp, int waitfor, struct thread *td, int commit, int called_from_renewthread) { struct nfsnode *np = VTONFS(vp); struct buf *bp; int i; struct buf *nbp; struct nfsmount *nmp = VFSTONFS(vp->v_mount); int error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos; int passone = 1, trycnt = 0; u_quad_t off, endoff, toff; struct ucred* wcred = NULL; struct buf **bvec = NULL; struct bufobj *bo; #ifndef NFS_COMMITBVECSIZ #define NFS_COMMITBVECSIZ 20 #endif struct buf *bvec_on_stack[NFS_COMMITBVECSIZ]; u_int bvecsize = 0, bveccount; struct timespec ts; if (called_from_renewthread != 0) slptimeo = hz; if (nmp->nm_flag & NFSMNT_INT) slpflag = PCATCH; if (!commit) passone = 0; bo = &vp->v_bufobj; /* * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the * server, but has not been committed to stable storage on the server * yet. On the first pass, the byte range is worked out and the commit * rpc is done. On the second pass, bwrite() is called to do the * job. */ again: off = (u_quad_t)-1; endoff = 0; bvecpos = 0; if (NFS_ISV34(vp) && commit) { if (bvec != NULL && bvec != bvec_on_stack) free(bvec, M_TEMP); /* * Count up how many buffers waiting for a commit. */ bveccount = 0; BO_LOCK(bo); TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { if (!BUF_ISLOCKED(bp) && (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) == (B_DELWRI | B_NEEDCOMMIT)) bveccount++; } /* * Allocate space to remember the list of bufs to commit. It is * important to use M_NOWAIT here to avoid a race with nfs_write. * If we can't get memory (for whatever reason), we will end up * committing the buffers one-by-one in the loop below. */ if (bveccount > NFS_COMMITBVECSIZ) { /* * Release the vnode interlock to avoid a lock * order reversal. */ BO_UNLOCK(bo); bvec = (struct buf **) malloc(bveccount * sizeof(struct buf *), M_TEMP, M_NOWAIT); BO_LOCK(bo); if (bvec == NULL) { bvec = bvec_on_stack; bvecsize = NFS_COMMITBVECSIZ; } else bvecsize = bveccount; } else { bvec = bvec_on_stack; bvecsize = NFS_COMMITBVECSIZ; } TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { if (bvecpos >= bvecsize) break; if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) { nbp = TAILQ_NEXT(bp, b_bobufs); continue; } if ((bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) != (B_DELWRI | B_NEEDCOMMIT)) { BUF_UNLOCK(bp); nbp = TAILQ_NEXT(bp, b_bobufs); continue; } BO_UNLOCK(bo); bremfree(bp); /* * Work out if all buffers are using the same cred * so we can deal with them all with one commit. * * NOTE: we are not clearing B_DONE here, so we have * to do it later on in this routine if we intend to * initiate I/O on the bp. * * Note: to avoid loopback deadlocks, we do not * assign b_runningbufspace. */ if (wcred == NULL) wcred = bp->b_wcred; else if (wcred != bp->b_wcred) wcred = NOCRED; vfs_busy_pages(bp, 0); BO_LOCK(bo); /* * bp is protected by being locked, but nbp is not * and vfs_busy_pages() may sleep. We have to * recalculate nbp. */ nbp = TAILQ_NEXT(bp, b_bobufs); /* * A list of these buffers is kept so that the * second loop knows which buffers have actually * been committed. This is necessary, since there * may be a race between the commit rpc and new * uncommitted writes on the file. */ bvec[bvecpos++] = bp; toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff; if (toff < off) off = toff; toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff); if (toff > endoff) endoff = toff; } BO_UNLOCK(bo); } if (bvecpos > 0) { /* * Commit data on the server, as required. * If all bufs are using the same wcred, then use that with * one call for all of them, otherwise commit each one * separately. */ if (wcred != NOCRED) retv = ncl_commit(vp, off, (int)(endoff - off), wcred, td); else { retv = 0; for (i = 0; i < bvecpos; i++) { off_t off, size; bp = bvec[i]; off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff; size = (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff); retv = ncl_commit(vp, off, (int)size, bp->b_wcred, td); if (retv) break; } } if (retv == NFSERR_STALEWRITEVERF) ncl_clearcommit(vp->v_mount); /* * Now, either mark the blocks I/O done or mark the * blocks dirty, depending on whether the commit * succeeded. */ for (i = 0; i < bvecpos; i++) { bp = bvec[i]; bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); if (!NFSCL_FORCEDISM(vp->v_mount) && retv) { /* * Error, leave B_DELWRI intact */ vfs_unbusy_pages(bp); brelse(bp); } else { /* * Success, remove B_DELWRI ( bundirty() ). * * b_dirtyoff/b_dirtyend seem to be NFS * specific. We should probably move that * into bundirty(). XXX */ bufobj_wref(bo); bp->b_flags |= B_ASYNC; bundirty(bp); bp->b_flags &= ~B_DONE; bp->b_ioflags &= ~BIO_ERROR; bp->b_dirtyoff = bp->b_dirtyend = 0; bufdone(bp); } } } /* * Start/do any write(s) that are required. */ loop: BO_LOCK(bo); TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) { if (waitfor != MNT_WAIT || passone) continue; error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, BO_LOCKPTR(bo), "nfsfsync", slpflag, slptimeo); if (error == 0) { BUF_UNLOCK(bp); goto loop; } if (error == ENOLCK) { error = 0; goto loop; } if (called_from_renewthread != 0) { /* * Return EIO so the flush will be retried * later. */ error = EIO; goto done; } if (newnfs_sigintr(nmp, td)) { error = EINTR; goto done; } if (slpflag == PCATCH) { slpflag = 0; slptimeo = 2 * hz; } goto loop; } if ((bp->b_flags & B_DELWRI) == 0) panic("nfs_fsync: not dirty"); if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT)) { BUF_UNLOCK(bp); continue; } BO_UNLOCK(bo); bremfree(bp); bp->b_flags |= B_ASYNC; bwrite(bp); if (newnfs_sigintr(nmp, td)) { error = EINTR; goto done; } goto loop; } if (passone) { passone = 0; BO_UNLOCK(bo); goto again; } if (waitfor == MNT_WAIT) { while (bo->bo_numoutput) { error = bufobj_wwait(bo, slpflag, slptimeo); if (error) { BO_UNLOCK(bo); if (called_from_renewthread != 0) { /* * Return EIO so that the flush will be * retried later. */ error = EIO; goto done; } error = newnfs_sigintr(nmp, td); if (error) goto done; if (slpflag == PCATCH) { slpflag = 0; slptimeo = 2 * hz; } BO_LOCK(bo); } } if (bo->bo_dirty.bv_cnt != 0 && commit) { BO_UNLOCK(bo); goto loop; } /* * Wait for all the async IO requests to drain */ BO_UNLOCK(bo); } else BO_UNLOCK(bo); if (NFSHASPNFS(nmp)) { nfscl_layoutcommit(vp, td); /* * Invalidate the attribute cache, since writes to a DS * won't update the size attribute. */ NFSLOCKNODE(np); np->n_attrstamp = 0; } else NFSLOCKNODE(np); if (np->n_flag & NWRITEERR) { error = np->n_error; np->n_flag &= ~NWRITEERR; } if (commit && bo->bo_dirty.bv_cnt == 0 && bo->bo_numoutput == 0) np->n_flag &= ~NMODIFIED; NFSUNLOCKNODE(np); done: if (bvec != NULL && bvec != bvec_on_stack) free(bvec, M_TEMP); if (error == 0 && commit != 0 && waitfor == MNT_WAIT && (bo->bo_dirty.bv_cnt != 0 || bo->bo_numoutput != 0)) { if (trycnt++ < 5) { /* try, try again... */ passone = 1; wcred = NULL; bvec = NULL; bvecsize = 0; goto again; } vn_printf(vp, "ncl_flush failed"); error = called_from_renewthread != 0 ? EIO : EBUSY; } if (error == 0) { nanouptime(&ts); NFSLOCKNODE(np); np->n_localmodtime = ts; NFSUNLOCKNODE(np); } return (error); } /* * NFS advisory byte-level locks. */ static int nfs_advlock(struct vop_advlock_args *ap) { struct vnode *vp = ap->a_vp; struct ucred *cred; struct nfsnode *np = VTONFS(ap->a_vp); struct proc *p = (struct proc *)ap->a_id; struct thread *td = curthread; /* XXX */ struct vattr va; int ret, error; u_quad_t size; struct nfsmount *nmp; error = NFSVOPLOCK(vp, LK_EXCLUSIVE); if (error != 0) return (EBADF); nmp = VFSTONFS(vp->v_mount); if (!NFS_ISV4(vp) || (nmp->nm_flag & NFSMNT_NOLOCKD) != 0) { if ((nmp->nm_flag & NFSMNT_NOLOCKD) != 0) { size = np->n_size; NFSVOPUNLOCK(vp); error = lf_advlock(ap, &(vp->v_lockf), size); } else { if (nfs_advlock_p != NULL) error = nfs_advlock_p(ap); else { NFSVOPUNLOCK(vp); error = ENOLCK; } } if (error == 0 && ap->a_op == F_SETLK) { error = NFSVOPLOCK(vp, LK_SHARED); if (error == 0) { /* Mark that a file lock has been acquired. */ NFSLOCKNODE(np); np->n_flag |= NHASBEENLOCKED; NFSUNLOCKNODE(np); NFSVOPUNLOCK(vp); } } return (error); } else if ((ap->a_flags & (F_POSIX | F_FLOCK)) != 0) { if (vp->v_type != VREG) { error = EINVAL; goto out; } if ((ap->a_flags & F_POSIX) != 0) cred = p->p_ucred; else cred = td->td_ucred; /* * If this is unlocking a write locked region, flush and * commit them before unlocking. This is required by * RFC3530 Sec. 9.3.2. */ if (ap->a_op == F_UNLCK && nfscl_checkwritelocked(vp, ap->a_fl, cred, td, ap->a_id, ap->a_flags)) (void) ncl_flush(vp, MNT_WAIT, td, 1, 0); /* * Mark NFS node as might have acquired a lock. * This is separate from NHASBEENLOCKED, because it must * be done before the nfsrpc_advlock() call, which might * add a nfscllock structure to the client state. * It is used to check for the case where a nfscllock * state structure cannot exist for the file. * Only done for "oneopenown" NFSv4.1/4.2 mounts. */ if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp)) { NFSLOCKNODE(np); np->n_flag |= NMIGHTBELOCKED; NFSUNLOCKNODE(np); } /* * Loop around doing the lock op, while a blocking lock * must wait for the lock op to succeed. */ do { ret = nfsrpc_advlock(vp, np->n_size, ap->a_op, ap->a_fl, 0, cred, td, ap->a_id, ap->a_flags); if (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) && ap->a_op == F_SETLK) { NFSVOPUNLOCK(vp); error = nfs_catnap(PZERO | PCATCH, ret, "ncladvl"); if (error) return (EINTR); NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); if (VN_IS_DOOMED(vp)) { error = EBADF; goto out; } } } while (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) && ap->a_op == F_SETLK); if (ret == NFSERR_DENIED) { error = EAGAIN; goto out; } else if (ret == EINVAL || ret == EBADF || ret == EINTR) { error = ret; goto out; } else if (ret != 0) { error = EACCES; goto out; } /* * Now, if we just got a lock, invalidate data in the buffer * cache, as required, so that the coherency conforms with * RFC3530 Sec. 9.3.2. */ if (ap->a_op == F_SETLK) { if ((np->n_flag & NMODIFIED) == 0) { np->n_attrstamp = 0; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); ret = VOP_GETATTR(vp, &va, cred); } if ((np->n_flag & NMODIFIED) || ret || np->n_change != va.va_filerev) { (void) ncl_vinvalbuf(vp, V_SAVE, td, 1); np->n_attrstamp = 0; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); ret = VOP_GETATTR(vp, &va, cred); if (!ret) { np->n_mtime = va.va_mtime; np->n_change = va.va_filerev; } } /* Mark that a file lock has been acquired. */ NFSLOCKNODE(np); np->n_flag |= NHASBEENLOCKED; NFSUNLOCKNODE(np); } } else error = EOPNOTSUPP; out: NFSVOPUNLOCK(vp); return (error); } /* * NFS advisory byte-level locks. */ static int nfs_advlockasync(struct vop_advlockasync_args *ap) { struct vnode *vp = ap->a_vp; u_quad_t size; int error; error = NFSVOPLOCK(vp, LK_SHARED); if (error) return (error); if (NFS_ISV4(vp)) { NFSVOPUNLOCK(vp); return (EOPNOTSUPP); } if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { size = VTONFS(vp)->n_size; NFSVOPUNLOCK(vp); error = lf_advlockasync(ap, &(vp->v_lockf), size); } else { NFSVOPUNLOCK(vp); error = EOPNOTSUPP; } return (error); } /* * Print out the contents of an nfsnode. */ static int nfs_print(struct vop_print_args *ap) { struct vnode *vp = ap->a_vp; struct nfsnode *np = VTONFS(vp); printf("\tfileid %jd fsid 0x%jx", (uintmax_t)np->n_vattr.na_fileid, (uintmax_t)np->n_vattr.na_fsid); if (vp->v_type == VFIFO) fifo_printinfo(vp); printf("\n"); return (0); } /* * nfs special file access vnode op. * Essentially just get vattr and then imitate iaccess() since the device is * local to the client. */ static int nfsspec_access(struct vop_access_args *ap) { struct vattr *vap; struct ucred *cred = ap->a_cred; struct vnode *vp = ap->a_vp; accmode_t accmode = ap->a_accmode; struct vattr vattr; int error; /* * Disallow write attempts on filesystems mounted read-only; * unless the file is a socket, fifo, or a block or character * device resident on the filesystem. */ if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { switch (vp->v_type) { case VREG: case VDIR: case VLNK: return (EROFS); default: break; } } vap = &vattr; error = VOP_GETATTR(vp, vap, cred); if (error) goto out; error = vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid, accmode, cred); out: return error; } /* * Read wrapper for fifos. */ static int nfsfifo_read(struct vop_read_args *ap) { struct nfsnode *np = VTONFS(ap->a_vp); int error; /* * Set access flag. */ NFSLOCKNODE(np); np->n_flag |= NACC; vfs_timestamp(&np->n_atim); NFSUNLOCKNODE(np); error = fifo_specops.vop_read(ap); return error; } /* * Write wrapper for fifos. */ static int nfsfifo_write(struct vop_write_args *ap) { struct nfsnode *np = VTONFS(ap->a_vp); /* * Set update flag. */ NFSLOCKNODE(np); np->n_flag |= NUPD; vfs_timestamp(&np->n_mtim); NFSUNLOCKNODE(np); return(fifo_specops.vop_write(ap)); } /* * Close wrapper for fifos. * * Update the times on the nfsnode then do fifo close. */ static int nfsfifo_close(struct vop_close_args *ap) { struct vnode *vp = ap->a_vp; struct nfsnode *np = VTONFS(vp); struct vattr vattr; struct timespec ts; NFSLOCKNODE(np); if (np->n_flag & (NACC | NUPD)) { vfs_timestamp(&ts); if (np->n_flag & NACC) np->n_atim = ts; if (np->n_flag & NUPD) np->n_mtim = ts; np->n_flag |= NCHG; if (vrefcnt(vp) == 1 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { VATTR_NULL(&vattr); if (np->n_flag & NACC) vattr.va_atime = np->n_atim; if (np->n_flag & NUPD) vattr.va_mtime = np->n_mtim; NFSUNLOCKNODE(np); (void)VOP_SETATTR(vp, &vattr, ap->a_cred); goto out; } } NFSUNLOCKNODE(np); out: return (fifo_specops.vop_close(ap)); } static int nfs_getacl(struct vop_getacl_args *ap) { int error; if (ap->a_type != ACL_TYPE_NFS4) return (EOPNOTSUPP); error = nfsrpc_getacl(ap->a_vp, ap->a_cred, ap->a_td, ap->a_aclp); if (error > NFSERR_STALE) { (void) nfscl_maperr(ap->a_td, error, (uid_t)0, (gid_t)0); error = EPERM; } return (error); } static int nfs_setacl(struct vop_setacl_args *ap) { int error; if (ap->a_type != ACL_TYPE_NFS4) return (EOPNOTSUPP); error = nfsrpc_setacl(ap->a_vp, ap->a_cred, ap->a_td, ap->a_aclp); if (error > NFSERR_STALE) { (void) nfscl_maperr(ap->a_td, error, (uid_t)0, (gid_t)0); error = EPERM; } return (error); } /* * VOP_ADVISE for NFS. * Just return 0 for any errors, since it is just a hint. */ static int nfs_advise(struct vop_advise_args *ap) { struct thread *td = curthread; struct nfsmount *nmp; uint64_t len; int error; /* * First do vop_stdadvise() to handle the buffer cache. */ error = vop_stdadvise(ap); if (error != 0) return (error); if (ap->a_start < 0 || ap->a_end < 0) return (0); if (ap->a_end == OFF_MAX) len = 0; else if (ap->a_end < ap->a_start) return (0); else len = ap->a_end - ap->a_start + 1; nmp = VFSTONFS(ap->a_vp->v_mount); mtx_lock(&nmp->nm_mtx); if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION || (NFSHASPNFS(nmp) && (nmp->nm_privflag & NFSMNTP_IOADVISETHRUMDS) == 0) || (nmp->nm_privflag & NFSMNTP_NOADVISE) != 0) { mtx_unlock(&nmp->nm_mtx); return (0); } mtx_unlock(&nmp->nm_mtx); error = nfsrpc_advise(ap->a_vp, ap->a_start, len, ap->a_advice, td->td_ucred, td); if (error == NFSERR_NOTSUPP) { mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NOADVISE; mtx_unlock(&nmp->nm_mtx); } return (0); } /* * nfs allocate call */ static int nfs_allocate(struct vop_allocate_args *ap) { struct vnode *vp = ap->a_vp; struct thread *td = curthread; struct nfsvattr nfsva; struct nfsmount *nmp; struct nfsnode *np; off_t alen; int attrflag, error, ret; struct timespec ts; struct uio io; attrflag = 0; nmp = VFSTONFS(vp->v_mount); np = VTONFS(vp); mtx_lock(&nmp->nm_mtx); if (NFSHASNFSV4(nmp) && nmp->nm_minorvers >= NFSV42_MINORVERSION && (nmp->nm_privflag & NFSMNTP_NOALLOCATE) == 0) { mtx_unlock(&nmp->nm_mtx); alen = *ap->a_len; if ((uint64_t)alen > nfs_maxalloclen) alen = nfs_maxalloclen; /* Check the file size limit. */ io.uio_offset = *ap->a_offset; io.uio_resid = alen; error = vn_rlimit_fsize(vp, &io, td); /* * Flush first to ensure that the allocate adds to the * file's allocation on the server. */ if (error == 0) { vnode_pager_clean_sync(vp); error = ncl_flush(vp, MNT_WAIT, td, 1, 0); } if (error == 0) error = nfsrpc_allocate(vp, *ap->a_offset, alen, &nfsva, &attrflag, ap->a_cred, td); if (error == 0) { *ap->a_offset += alen; *ap->a_len -= alen; nanouptime(&ts); NFSLOCKNODE(np); np->n_localmodtime = ts; NFSUNLOCKNODE(np); } else if (error == NFSERR_NOTSUPP) { mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NOALLOCATE; mtx_unlock(&nmp->nm_mtx); error = EINVAL; } } else { mtx_unlock(&nmp->nm_mtx); error = EINVAL; } if (attrflag != 0) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error == 0 && ret != 0) error = ret; } if (error != 0) error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); return (error); } /* * nfs deallocate call */ static int nfs_deallocate(struct vop_deallocate_args *ap) { struct vnode *vp = ap->a_vp; struct thread *td = curthread; struct nfsvattr nfsva; struct nfsmount *nmp; struct nfsnode *np; off_t tlen, mlen; int attrflag, error, ret; bool clipped; struct timespec ts; error = 0; attrflag = 0; nmp = VFSTONFS(vp->v_mount); np = VTONFS(vp); mtx_lock(&nmp->nm_mtx); if (NFSHASNFSV4(nmp) && nmp->nm_minorvers >= NFSV42_MINORVERSION && (nmp->nm_privflag & NFSMNTP_NODEALLOCATE) == 0) { mtx_unlock(&nmp->nm_mtx); tlen = omin(OFF_MAX - *ap->a_offset, *ap->a_len); NFSCL_DEBUG(4, "dealloc: off=%jd len=%jd maxfilesize=%ju\n", (intmax_t)*ap->a_offset, (intmax_t)tlen, (uintmax_t)nmp->nm_maxfilesize); if ((uint64_t)*ap->a_offset >= nmp->nm_maxfilesize) { /* Avoid EFBIG error return from the NFSv4.2 server. */ *ap->a_len = 0; return (0); } clipped = false; if ((uint64_t)*ap->a_offset + tlen > nmp->nm_maxfilesize) tlen = nmp->nm_maxfilesize - *ap->a_offset; if ((uint64_t)*ap->a_offset < np->n_size) { /* Limit the len to nfs_maxalloclen before EOF. */ mlen = omin((off_t)np->n_size - *ap->a_offset, tlen); if ((uint64_t)mlen > nfs_maxalloclen) { NFSCL_DEBUG(4, "dealloc: tlen maxalloclen\n"); tlen = nfs_maxalloclen; clipped = true; } } if (error == 0) error = ncl_vinvalbuf(vp, V_SAVE, td, 1); if (error == 0) { vnode_pager_purge_range(vp, *ap->a_offset, *ap->a_offset + tlen); error = nfsrpc_deallocate(vp, *ap->a_offset, tlen, &nfsva, &attrflag, ap->a_cred, td); NFSCL_DEBUG(4, "dealloc: rpc=%d\n", error); } if (error == 0) { NFSCL_DEBUG(4, "dealloc: attrflag=%d na_size=%ju\n", attrflag, (uintmax_t)nfsva.na_size); nanouptime(&ts); NFSLOCKNODE(np); np->n_localmodtime = ts; NFSUNLOCKNODE(np); if (attrflag != 0) { if ((uint64_t)*ap->a_offset < nfsva.na_size) *ap->a_offset += omin((off_t) nfsva.na_size - *ap->a_offset, tlen); } if (clipped && tlen < *ap->a_len) *ap->a_len -= tlen; else *ap->a_len = 0; } else if (error == NFSERR_NOTSUPP) { mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NODEALLOCATE; mtx_unlock(&nmp->nm_mtx); } } else { mtx_unlock(&nmp->nm_mtx); error = EIO; } /* * If the NFS server cannot perform the Deallocate operation, just call * vop_stddeallocate() to perform it. */ if (error != 0 && error != NFSERR_FBIG && error != NFSERR_INVAL) { error = vop_stddeallocate(ap); NFSCL_DEBUG(4, "dealloc: stddeallocate=%d\n", error); } if (attrflag != 0) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error == 0 && ret != 0) error = ret; } if (error != 0) error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); return (error); } /* * nfs copy_file_range call */ static int nfs_copy_file_range(struct vop_copy_file_range_args *ap) { struct vnode *invp = ap->a_invp; struct vnode *outvp = ap->a_outvp; struct mount *mp; vm_object_t invp_obj; struct nfsvattr innfsva, outnfsva; 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, 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 && (ap->a_flags & COPY_FILE_RANGE_CLONE) == 0) || (invp != outvp && invp->v_mount != outvp->v_mount)) { generic_copy: return (ENOSYS); } 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 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; VOP_UNLOCK(outvp); if (mp != NULL) vn_finished_write(mp); mp = NULL; error = vn_lock(invp, invp_lock); if (error == 0) VOP_UNLOCK(invp); } } if (mp != NULL) vn_finished_write(mp); } while (error == 0); if (error != 0) return (error); /* * 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 || (mustclone && (!NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_CLONEBLKSIZE) || nmp->nm_cloneblksize == 0))) { mtx_unlock(&nmp->nm_mtx); VOP_UNLOCK(invp); if (!onevp) VOP_UNLOCK(outvp); /* For onevp, same as invp. */ if (mp != NULL) vn_finished_write(mp); goto generic_copy; } mtx_unlock(&nmp->nm_mtx); /* * Do the vn_rlimit_fsize() check. Should this be above the VOP layer? */ io.uio_offset = *ap->a_outoffp; io.uio_resid = *ap->a_lenp; error = vn_rlimit_fsizex(outvp, &io, 0, &r, ap->a_fsizetd); *ap->a_lenp = io.uio_resid; /* * No need to call vn_rlimit_fsizex_res before return, since the uio is * local. */ /* * Flush the input file so that the data is up to date before * the copy. Flush writes for the output file so that they * do not overwrite the data copied to the output file by the Copy. * Set the commit argument for both flushes so that the data is on * stable storage before the Copy RPC. This is done in case the * server reboots during the Copy and needs to be redone. */ if (error == 0) { 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); if (mp != NULL) vn_finished_write(mp); goto relock; } vnode_pager_clean_sync(invp); } error = ncl_flush(invp, MNT_WAIT, curthread, 1, 0); } if (error == 0) error = ncl_vinvalbuf(outvp, V_SAVE, curthread, 0); /* Do the actual NFSv4.2 RPC. */ ret = ret2 = 0; len = *ap->a_lenp; mtx_lock(&nmp->nm_mtx); if ((nmp->nm_privflag & NFSMNTP_NOCONSECUTIVE) == 0) consecutive = true; else consecutive = false; mtx_unlock(&nmp->nm_mtx); 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); if (error == 0) { /* * Clip "len" at va_size so that RFC compliant servers * will not reply NFSERR_INVAL. * Setting "len == 0" for the RPC would be preferred, * but some Linux servers do not support that. * If the len is being set to 0, do a Setattr RPC to * set the server's atime. This behaviour was the * preferred one for the FreeBSD "collective". */ if (inoff >= vap->va_size) { *ap->a_lenp = len = 0; if ((nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) { VATTR_NULL(&va); va.va_atime.tv_sec = 0; va.va_atime.tv_nsec = 0; va.va_vaflags = VA_UTIMES_NULL; inattrflag = 0; error = nfsrpc_setattr(invp, &va, NULL, ap->a_incred, curthread, &innfsva, &inattrflag); if (inattrflag != 0) ret = nfscl_loadattrcache(&invp, &innfsva, NULL, 0, 1); if (error == 0 && ret != 0) error = ret; } } 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/Clone RPC needs to be retried. */ while (len > 0 && error == 0) { inattrflag = outattrflag = 0; len2 = len; 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) ret2 = nfscl_loadattrcache(&outvp, &outnfsva, NULL, 1, 1); if (error == 0) { if (consecutive == false) { if (len2 == len) { mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NOCONSECUTIVE; mtx_unlock(&nmp->nm_mtx); } else error = NFSERR_OFFLOADNOREQS; } *ap->a_lenp = len2; len = 0; if (len2 > 0 && must_commit && error == 0) error = ncl_commit(outvp, outoff, *ap->a_lenp, ap->a_outcred, curthread); if (error == 0 && ret != 0) error = ret; if (error == 0 && ret2 != 0) error = ret2; } else if (error == NFSERR_OFFLOADNOREQS && consecutive) { /* * Try consecutive == false, which is ok only if all * bytes are copied. * If only some bytes were copied when consecutive * is false, there is no way to know which bytes * still need to be written. */ consecutive = false; error = 0; } else if (error == NFSERR_ACCES && tryoutcred) { /* 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) { /* * Server rebooted, so do it all again. */ *ap->a_inoffp = inoff; *ap->a_outoffp = outoff; len = *ap->a_lenp; must_commit = false; error = 0; } } VOP_UNLOCK(invp); 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 == 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 * try this for NFSERR_ACCES failures for the Copy. * For NFSERR_NOTSUPP and NFSERR_OFFLOADNOREQS, the Copy can * never succeed, so disable it. */ if (error != NFSERR_ACCES && error != ENOSYS) { /* Can never do Copy on this mount. */ mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NOCOPY; mtx_unlock(&nmp->nm_mtx); } *ap->a_inoffp = inoff; *ap->a_outoffp = outoff; error = vn_generic_copy_file_range(ap->a_invp, ap->a_inoffp, ap->a_outvp, ap->a_outoffp, ap->a_lenp, ap->a_flags, ap->a_incred, ap->a_outcred, ap->a_fsizetd); } else if (error != 0) *ap->a_lenp = 0; if (error != 0) error = nfscl_maperr(curthread, error, (uid_t)0, (gid_t)0); return (error); } /* * nfs ioctl call */ static int nfs_ioctl(struct vop_ioctl_args *ap) { struct vnode *vp = ap->a_vp; struct nfsvattr nfsva; struct nfsmount *nmp; int attrflag, content, error, ret; bool eof = false; /* shut up compiler. */ /* Do the actual NFSv4.2 RPC. */ switch (ap->a_command) { case FIOSEEKDATA: content = NFSV4CONTENT_DATA; break; case FIOSEEKHOLE: content = NFSV4CONTENT_HOLE; break; default: return (ENOTTY); } error = vn_lock(vp, LK_EXCLUSIVE); if (error != 0) return (EBADF); if (vp->v_type != VREG) { VOP_UNLOCK(vp); return (ENOTTY); } nmp = VFSTONFS(vp->v_mount); if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION) { VOP_UNLOCK(vp); error = vop_stdioctl(ap); return (error); } attrflag = 0; if (*((off_t *)ap->a_data) >= VTONFS(vp)->n_size) error = ENXIO; else { /* * Flush all writes, so that the server is up to date. * Although a Commit is not required, the commit argument * is set so that, for a pNFS File/Flexible File Layout * server, the LayoutCommit will be done to ensure the file * size is up to date on the Metadata Server. */ vnode_pager_clean_sync(vp); error = ncl_flush(vp, MNT_WAIT, ap->a_td, 1, 0); if (error == 0) error = nfsrpc_seek(vp, (off_t *)ap->a_data, &eof, content, ap->a_cred, &nfsva, &attrflag); /* If at eof for FIOSEEKDATA, return ENXIO. */ if (eof && error == 0 && content == NFSV4CONTENT_DATA) error = ENXIO; } if (attrflag != 0) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error == 0 && ret != 0) error = ret; } NFSVOPUNLOCK(vp); if (error != 0) error = ENXIO; return (error); } /* * nfs getextattr call */ static int nfs_getextattr(struct vop_getextattr_args *ap) { struct vnode *vp = ap->a_vp; struct nfsmount *nmp; struct ucred *cred; struct thread *td = ap->a_td; struct nfsvattr nfsva; ssize_t len; int attrflag, error, ret; nmp = VFSTONFS(vp->v_mount); mtx_lock(&nmp->nm_mtx); if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION || (nmp->nm_privflag & NFSMNTP_NOXATTR) != 0 || ap->a_attrnamespace != EXTATTR_NAMESPACE_USER) { mtx_unlock(&nmp->nm_mtx); return (EOPNOTSUPP); } mtx_unlock(&nmp->nm_mtx); cred = ap->a_cred; if (cred == NULL) cred = td->td_ucred; /* Do the actual NFSv4.2 Optional Extended Attribute (RFC-8276) RPC. */ attrflag = 0; error = nfsrpc_getextattr(vp, ap->a_name, ap->a_uio, &len, &nfsva, &attrflag, cred, td); if (attrflag != 0) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error == 0 && ret != 0) error = ret; } if (error == 0 && ap->a_size != NULL) *ap->a_size = len; switch (error) { case NFSERR_NOTSUPP: case NFSERR_OPILLEGAL: mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NOXATTR; mtx_unlock(&nmp->nm_mtx); error = EOPNOTSUPP; break; case NFSERR_NOXATTR: case NFSERR_XATTR2BIG: error = ENOATTR; break; default: error = nfscl_maperr(td, error, 0, 0); break; } return (error); } /* * nfs setextattr call */ static int nfs_setextattr(struct vop_setextattr_args *ap) { struct vnode *vp = ap->a_vp; struct nfsmount *nmp; struct ucred *cred; struct thread *td = ap->a_td; struct nfsvattr nfsva; int attrflag, error, ret; nmp = VFSTONFS(vp->v_mount); mtx_lock(&nmp->nm_mtx); if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION || (nmp->nm_privflag & NFSMNTP_NOXATTR) != 0 || ap->a_attrnamespace != EXTATTR_NAMESPACE_USER) { mtx_unlock(&nmp->nm_mtx); return (EOPNOTSUPP); } mtx_unlock(&nmp->nm_mtx); if (ap->a_uio->uio_resid < 0) return (EINVAL); cred = ap->a_cred; if (cred == NULL) cred = td->td_ucred; /* Do the actual NFSv4.2 Optional Extended Attribute (RFC-8276) RPC. */ attrflag = 0; error = nfsrpc_setextattr(vp, ap->a_name, ap->a_uio, &nfsva, &attrflag, cred, td); if (attrflag != 0) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error == 0 && ret != 0) error = ret; } switch (error) { case NFSERR_NOTSUPP: case NFSERR_OPILLEGAL: mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NOXATTR; mtx_unlock(&nmp->nm_mtx); error = EOPNOTSUPP; break; case NFSERR_NOXATTR: case NFSERR_XATTR2BIG: error = ENOATTR; break; default: error = nfscl_maperr(td, error, 0, 0); break; } return (error); } /* * nfs listextattr call */ static int nfs_listextattr(struct vop_listextattr_args *ap) { struct vnode *vp = ap->a_vp; struct nfsmount *nmp; struct ucred *cred; struct thread *td = ap->a_td; struct nfsvattr nfsva; size_t len, len2; uint64_t cookie; int attrflag, error, ret; bool eof; nmp = VFSTONFS(vp->v_mount); mtx_lock(&nmp->nm_mtx); if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION || (nmp->nm_privflag & NFSMNTP_NOXATTR) != 0 || ap->a_attrnamespace != EXTATTR_NAMESPACE_USER) { mtx_unlock(&nmp->nm_mtx); return (EOPNOTSUPP); } mtx_unlock(&nmp->nm_mtx); cred = ap->a_cred; if (cred == NULL) cred = td->td_ucred; /* Loop around doing List Extended Attribute RPCs. */ eof = false; cookie = 0; len2 = 0; error = 0; while (!eof && error == 0) { len = nmp->nm_rsize; attrflag = 0; error = nfsrpc_listextattr(vp, &cookie, ap->a_uio, &len, &eof, &nfsva, &attrflag, cred, td); if (attrflag != 0) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error == 0 && ret != 0) error = ret; } if (error == 0) { len2 += len; if (len2 > SSIZE_MAX) error = ENOATTR; } } if (error == 0 && ap->a_size != NULL) *ap->a_size = len2; switch (error) { case NFSERR_NOTSUPP: case NFSERR_OPILLEGAL: mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NOXATTR; mtx_unlock(&nmp->nm_mtx); error = EOPNOTSUPP; break; case NFSERR_NOXATTR: case NFSERR_XATTR2BIG: error = ENOATTR; break; default: error = nfscl_maperr(td, error, 0, 0); break; } return (error); } /* * nfs setextattr call */ static int nfs_deleteextattr(struct vop_deleteextattr_args *ap) { struct vnode *vp = ap->a_vp; struct nfsmount *nmp; struct nfsvattr nfsva; int attrflag, error, ret; nmp = VFSTONFS(vp->v_mount); mtx_lock(&nmp->nm_mtx); if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION || (nmp->nm_privflag & NFSMNTP_NOXATTR) != 0 || ap->a_attrnamespace != EXTATTR_NAMESPACE_USER) { mtx_unlock(&nmp->nm_mtx); return (EOPNOTSUPP); } mtx_unlock(&nmp->nm_mtx); /* Do the actual NFSv4.2 Optional Extended Attribute (RFC-8276) RPC. */ attrflag = 0; error = nfsrpc_rmextattr(vp, ap->a_name, &nfsva, &attrflag, ap->a_cred, ap->a_td); if (attrflag != 0) { ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); if (error == 0 && ret != 0) error = ret; } switch (error) { case NFSERR_NOTSUPP: case NFSERR_OPILLEGAL: mtx_lock(&nmp->nm_mtx); nmp->nm_privflag |= NFSMNTP_NOXATTR; mtx_unlock(&nmp->nm_mtx); error = EOPNOTSUPP; break; case NFSERR_NOXATTR: case NFSERR_XATTR2BIG: error = ENOATTR; break; default: error = nfscl_maperr(ap->a_td, error, 0, 0); break; } return (error); } /* * Return POSIX pathconf information applicable to nfs filesystems. */ static int nfs_pathconf(struct vop_pathconf_args *ap) { struct nfsv3_pathconf pc; struct nfsvattr nfsva; struct vnode *vp = ap->a_vp; 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; nmp = VFSTONFS(vp->v_mount); 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_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, _PC_HAS_NAMEDATTR and * _PC_CLONE_BLKSIZE as well. */ 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) return (error); } else if (NFS_ISV4(vp) && ap->a_name == _PC_NAMEDATTR_ENABLED && (np->n_flag & NNAMEDNOTSUPP) == 0) { struct nfsfh *nfhp; error = nfsrpc_openattr(nmp, vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, false, td->td_ucred, td, &nfsva, &nfhp, &attrflag); named_enabled = true; if (error == 0) { free(nfhp, M_NFSFH); } else if (error == NFSERR_NOTSUPP) { named_enabled = false; NFSLOCKNODE(np); np->n_flag |= NNAMEDNOTSUPP; NFSUNLOCKNODE(np); } error = 0; } else { /* * For NFSv2 (or NFSv3 when not one of the above 4 a_names), * just fake them. */ pc.pc_linkmax = NFS_LINK_MAX; pc.pc_namemax = NFS_MAXNAMLEN; pc.pc_notrunc = 1; pc.pc_chownrestricted = 1; pc.pc_caseinsensitive = 0; pc.pc_casepreserving = 1; error = 0; } switch (ap->a_name) { case _PC_LINK_MAX: #ifdef _LP64 *ap->a_retval = pc.pc_linkmax; #else *ap->a_retval = MIN(LONG_MAX, pc.pc_linkmax); #endif break; case _PC_NAME_MAX: *ap->a_retval = pc.pc_namemax; break; case _PC_PIPE_BUF: if (ap->a_vp->v_type == VDIR || ap->a_vp->v_type == VFIFO) *ap->a_retval = PIPE_BUF; else error = EINVAL; break; case _PC_CHOWN_RESTRICTED: *ap->a_retval = pc.pc_chownrestricted; break; case _PC_NO_TRUNC: *ap->a_retval = pc.pc_notrunc; break; case _PC_ACL_NFS4: if (NFS_ISV4(vp) && nfsrv_useacl != 0 && attrflag != 0 && NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) *ap->a_retval = 1; else *ap->a_retval = 0; break; case _PC_ACL_PATH_MAX: if (NFS_ISV4(vp)) *ap->a_retval = ACL_MAX_ENTRIES; else *ap->a_retval = 3; break; case _PC_PRIO_IO: *ap->a_retval = 0; break; case _PC_SYNC_IO: *ap->a_retval = 0; break; case _PC_ALLOC_SIZE_MIN: *ap->a_retval = vp->v_mount->mnt_stat.f_bsize; break; case _PC_FILESIZEBITS: if (NFS_ISV34(vp)) *ap->a_retval = 64; else *ap->a_retval = 32; break; case _PC_REC_INCR_XFER_SIZE: *ap->a_retval = vp->v_mount->mnt_stat.f_iosize; break; case _PC_REC_MAX_XFER_SIZE: *ap->a_retval = -1; /* means ``unlimited'' */ break; case _PC_REC_MIN_XFER_SIZE: *ap->a_retval = vp->v_mount->mnt_stat.f_iosize; break; case _PC_REC_XFER_ALIGN: *ap->a_retval = PAGE_SIZE; break; case _PC_SYMLINK_MAX: *ap->a_retval = NFS_MAXPATHLEN; break; case _PC_MIN_HOLE_SIZE: /* Only some NFSv4.2 servers support Seek for Holes. */ *ap->a_retval = 0; if (NFS_ISV4(vp) && nmp->nm_minorvers == NFSV42_MINORVERSION) { /* * NFSv4.2 doesn't have an attribute for hole size, * so all we can do is see if the Seek operation is * supported and then use f_iosize as a "best guess". */ mtx_lock(&nmp->nm_mtx); if ((nmp->nm_privflag & NFSMNTP_SEEKTESTED) == 0) { mtx_unlock(&nmp->nm_mtx); off = 0; attrflag = 0; error = nfsrpc_seek(vp, &off, &eof, NFSV4CONTENT_HOLE, td->td_ucred, &nfsva, &attrflag); if (attrflag != 0) (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); mtx_lock(&nmp->nm_mtx); if (error == NFSERR_NOTSUPP) nmp->nm_privflag |= NFSMNTP_SEEKTESTED; else nmp->nm_privflag |= NFSMNTP_SEEKTESTED | NFSMNTP_SEEK; error = 0; } if ((nmp->nm_privflag & NFSMNTP_SEEK) != 0) *ap->a_retval = vp->v_mount->mnt_stat.f_iosize; mtx_unlock(&nmp->nm_mtx); } break; case _PC_NAMEDATTR_ENABLED: if (named_enabled) *ap->a_retval = 1; else *ap->a_retval = 0; break; case _PC_HAS_NAMEDATTR: if (has_namedattr) *ap->a_retval = 1; else *ap->a_retval = 0; break; case _PC_HAS_HIDDENSYSTEM: if (NFS_ISV4(vp) && NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_HIDDEN) && NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_SYSTEM)) *ap->a_retval = 1; else *ap->a_retval = 0; break; case _PC_CLONE_BLKSIZE: *ap->a_retval = clone_blksize; break; default: error = vop_stdpathconf(ap); break; } return (error); } diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 5ba86314ead1..eb6ba285f8fe 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -1,7511 +1,7511 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 #include /* * Functions that perform the vfs operations required by the routines in * nfsd_serv.c. It is hoped that this change will make the server more * portable. */ #include #include #include #include #include #include #include #include #include #include #include FEATURE(nfsd, "NFSv4 server"); extern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; extern int nfsrv_useacl; extern int newnfs_numnfsd; extern int nfsrv_sessionhashsize; extern struct nfslayouthash *nfslayouthash; extern int nfsrv_layouthashsize; extern struct mtx nfsrv_dslock_mtx; extern int nfs_pnfsiothreads; extern volatile int nfsrv_devidcnt; extern int nfsrv_maxpnfsmirror; extern uint32_t nfs_srvmaxio; extern int nfs_bufpackets; extern u_long sb_max_adj; extern struct nfsv4lock nfsv4rootfs_lock; NFSD_VNET_DECLARE(int, nfsrv_numnfsd); NFSD_VNET_DECLARE(struct nfsrv_stablefirst, nfsrv_stablefirst); NFSD_VNET_DECLARE(SVCPOOL *, nfsrvd_pool); NFSD_VNET_DECLARE(struct nfsclienthashhead *, nfsclienthash); NFSD_VNET_DECLARE(struct nfslockhashhead *, nfslockhash); NFSD_VNET_DECLARE(struct nfssessionhash *, nfssessionhash); NFSD_VNET_DECLARE(struct nfsv4lock, nfsd_suspend_lock); NFSD_VNET_DECLARE(struct nfsstatsv1 *, nfsstatsv1_p); NFSDLOCKMUTEX; NFSSTATESPINLOCK; struct mtx nfsrc_udpmtx; struct mtx nfs_v4root_mutex; struct mtx nfsrv_dontlistlock_mtx; struct mtx nfsrv_recalllock_mtx; struct nfsrvfh nfs_pubfh; int nfs_pubfhset = 0; int nfsd_debuglevel = 0; static pid_t nfsd_master_pid = (pid_t)-1; static char nfsd_master_comm[MAXCOMLEN + 1]; static struct timeval nfsd_master_start; static uint32_t nfsv4_sysid = 0; static fhandle_t zerofh; NFSD_VNET_DEFINE(struct proc *, nfsd_master_proc) = NULL; NFSD_VNET_DEFINE(struct nfsrvhashhead *, nfsrvudphashtbl); NFSD_VNET_DEFINE(struct nfsrchash_bucket *, nfsrchash_table); NFSD_VNET_DEFINE(struct nfsrchash_bucket *, nfsrcahash_table); NFSD_VNET_DEFINE(struct nfsrvfh, nfs_rootfh); NFSD_VNET_DEFINE(int, nfs_rootfhset) = 0; NFSD_VNET_DEFINE(struct callout, nfsd_callout); NFSD_VNET_DEFINE_STATIC(struct mount *, nfsv4root_mnt); NFSD_VNET_DEFINE_STATIC(struct vfsoptlist, nfsv4root_opt); NFSD_VNET_DEFINE_STATIC(struct vfsoptlist, nfsv4root_newopt); NFSD_VNET_DEFINE_STATIC(bool, nfsrv_suspend_nfsd) = false; NFSD_VNET_DEFINE_STATIC(bool, nfsrv_mntinited) = false; static int nfssvc_srvcall(struct thread *, struct nfssvc_args *, struct ucred *); static void nfsvno_updateds(struct vnode *, struct ucred *, struct thread *); int nfsrv_enable_crossmntpt = 1; static int nfs_commit_blks; static int nfs_commit_miss; extern int nfsrv_issuedelegs; extern int nfsrv_dolocallocks; extern struct nfsdevicehead nfsrv_devidhead; /* Map d_type to vnode type. */ static uint8_t dtype_to_vnode[DT_WHT + 1] = { VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON }; static int nfsrv_createiovec(int, struct mbuf **, struct mbuf **, struct iovec **); static int nfsrv_createiovec_extpgs(int, int, struct mbuf **, struct mbuf **, struct iovec **); static int nfsrv_createiovecw(int, struct mbuf *, char *, struct iovec **, int *); static void nfs_dtypetovtype(struct nfsvattr *, struct vnode *, uint8_t); static void nfsrv_pnfscreate(struct vnode *, struct vattr *, struct ucred *, NFSPROC_T *); static void nfsrv_pnfsremovesetup(struct vnode *, NFSPROC_T *, struct vnode **, int *, char *, fhandle_t *); static void nfsrv_pnfsremove(struct vnode **, int, char *, fhandle_t *, NFSPROC_T *); static int nfsrv_proxyds(struct vnode *, off_t, int, struct ucred *, struct thread *, int, struct mbuf **, char *, struct mbuf **, struct nfsvattr *, struct acl *, off_t *, int, bool *); static int nfsrv_setextattr(struct vnode *, struct nfsvattr *, NFSPROC_T *); static int nfsrv_readdsrpc(fhandle_t *, off_t, int, struct ucred *, NFSPROC_T *, struct nfsmount *, struct mbuf **, struct mbuf **); static int nfsrv_writedsrpc(fhandle_t *, off_t, int, struct ucred *, NFSPROC_T *, struct vnode *, struct nfsmount **, int, struct mbuf **, char *, int *); static int nfsrv_allocatedsrpc(fhandle_t *, off_t, off_t, struct ucred *, NFSPROC_T *, struct vnode *, struct nfsmount **, int, int *); static int nfsrv_deallocatedsrpc(fhandle_t *, off_t, off_t, struct ucred *, NFSPROC_T *, struct vnode *, struct nfsmount **, int, int *); static int nfsrv_setacldsrpc(fhandle_t *, struct ucred *, NFSPROC_T *, struct vnode *, struct nfsmount **, int, struct acl *, int *); static int nfsrv_setattrdsrpc(fhandle_t *, struct ucred *, NFSPROC_T *, struct vnode *, struct nfsmount **, int, struct nfsvattr *, int *); static int nfsrv_getattrdsrpc(fhandle_t *, struct ucred *, NFSPROC_T *, struct vnode *, struct nfsmount *, struct nfsvattr *); static int nfsrv_seekdsrpc(fhandle_t *, off_t *, int, bool *, struct ucred *, NFSPROC_T *, struct nfsmount *); static int nfsrv_putfhname(fhandle_t *, char *); static int nfsrv_pnfslookupds(struct vnode *, struct vnode *, struct pnfsdsfile *, struct vnode **, NFSPROC_T *); static void nfsrv_pnfssetfh(struct vnode *, struct pnfsdsfile *, char *, char *, struct vnode *, NFSPROC_T *); static int nfsrv_dsremove(struct vnode *, char *, struct ucred *, NFSPROC_T *); static int nfsrv_dssetacl(struct vnode *, struct acl *, struct ucred *, NFSPROC_T *); static int nfsrv_pnfsstatfs(struct statfs *, struct mount *); int nfs_pnfsio(task_fn_t *, void *); SYSCTL_NODE(_vfs, OID_AUTO, nfsd, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "NFS server"); SYSCTL_INT(_vfs_nfsd, OID_AUTO, mirrormnt, CTLFLAG_RW, &nfsrv_enable_crossmntpt, 0, "Enable nfsd to cross mount points"); SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks, 0, ""); SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, 0, ""); SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW, &nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations"); SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW, &nfsd_debuglevel, 0, "Debug level for NFS server"); NFSD_VNET_DECLARE(int, nfsd_enable_stringtouid); SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, CTLFLAG_NFSD_VNET | CTLFLAG_RW, &NFSD_VNET_NAME(nfsd_enable_stringtouid), 0, "Enable nfsd to accept numeric owner_names"); static int nfsrv_pnfsgetdsattr = 1; SYSCTL_INT(_vfs_nfsd, OID_AUTO, pnfsgetdsattr, CTLFLAG_RW, &nfsrv_pnfsgetdsattr, 0, "When set getattr gets DS attributes via RPC"); static bool nfsrv_recalldeleg = false; SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, recalldeleg, CTLFLAG_RW, &nfsrv_recalldeleg, 0, "When set remove/rename recalls delegations for same client"); /* * nfsrv_dsdirsize can only be increased and only when the nfsd threads are * not running. * The dsN subdirectories for the increased values must have been created * on all DS servers before this increase is done. */ u_int nfsrv_dsdirsize = 20; static int sysctl_dsdirsize(SYSCTL_HANDLER_ARGS) { int error, newdsdirsize; newdsdirsize = nfsrv_dsdirsize; error = sysctl_handle_int(oidp, &newdsdirsize, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (newdsdirsize <= nfsrv_dsdirsize || newdsdirsize > 10000 || newnfs_numnfsd != 0) return (EINVAL); nfsrv_dsdirsize = newdsdirsize; return (0); } SYSCTL_PROC(_vfs_nfsd, OID_AUTO, dsdirsize, CTLTYPE_UINT | CTLFLAG_MPSAFE | CTLFLAG_RW, 0, sizeof(nfsrv_dsdirsize), sysctl_dsdirsize, "IU", "Number of dsN subdirs on the DS servers"); /* * nfs_srvmaxio can only be increased and only when the nfsd threads are * not running. The setting must be a power of 2, with the current limit of * 1Mbyte. */ static int sysctl_srvmaxio(SYSCTL_HANDLER_ARGS) { int error; u_int newsrvmaxio; uint64_t tval; newsrvmaxio = nfs_srvmaxio; error = sysctl_handle_int(oidp, &newsrvmaxio, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (newsrvmaxio == nfs_srvmaxio) return (0); if (newsrvmaxio < nfs_srvmaxio) { printf("nfsd: vfs.nfsd.srvmaxio can only be increased\n"); return (EINVAL); } if (newsrvmaxio > 1048576) { printf("nfsd: vfs.nfsd.srvmaxio cannot be > 1Mbyte\n"); return (EINVAL); } if ((newsrvmaxio & (newsrvmaxio - 1)) != 0) { printf("nfsd: vfs.nfsd.srvmaxio must be a power of 2\n"); return (EINVAL); } /* * Check that kern.ipc.maxsockbuf is large enough for * newsrviomax, given the setting of vfs.nfs.bufpackets. */ if ((newsrvmaxio + NFS_MAXXDR) * nfs_bufpackets > sb_max_adj) { /* * Suggest vfs.nfs.bufpackets * maximum RPC message for * sb_max_adj. */ tval = (newsrvmaxio + NFS_MAXXDR) * nfs_bufpackets; /* * Convert suggested sb_max_adj value to a suggested * sb_max value, which is what is set via kern.ipc.maxsockbuf. * Perform the inverse calculation of (from uipc_sockbuf.c): * sb_max_adj = (u_quad_t)sb_max * MCLBYTES / * (MSIZE + MCLBYTES); * XXX If the calculation of sb_max_adj from sb_max changes, * this calculation must be changed as well. */ tval *= (MSIZE + MCLBYTES); /* Brackets for readability. */ tval += MCLBYTES - 1; /* Round up divide. */ tval /= MCLBYTES; printf("nfsd: set kern.ipc.maxsockbuf to a minimum of " "%ju to support %ubyte NFS I/O\n", (uintmax_t)tval, newsrvmaxio); return (EINVAL); } NFSD_LOCK(); if (newnfs_numnfsd != 0) { NFSD_UNLOCK(); printf("nfsd: cannot set vfs.nfsd.srvmaxio when nfsd " "threads are running\n"); return (EINVAL); } nfs_srvmaxio = newsrvmaxio; NFSD_UNLOCK(); return (0); } SYSCTL_PROC(_vfs_nfsd, OID_AUTO, srvmaxio, CTLTYPE_UINT | CTLFLAG_MPSAFE | CTLFLAG_RW, NULL, 0, sysctl_srvmaxio, "IU", "Maximum I/O size in bytes"); static int sysctl_dolocallocks(SYSCTL_HANDLER_ARGS) { int error, igotlock, newdolocallocks; newdolocallocks = nfsrv_dolocallocks; error = sysctl_handle_int(oidp, &newdolocallocks, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (newdolocallocks == nfsrv_dolocallocks) return (0); if (jailed(curthread->td_ucred)) return (EINVAL); NFSLOCKV4ROOTMUTEX(); do { igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); } while (!igotlock); NFSUNLOCKV4ROOTMUTEX(); nfsrv_dolocallocks = newdolocallocks; NFSLOCKV4ROOTMUTEX(); nfsv4_unlock(&nfsv4rootfs_lock, 0); NFSUNLOCKV4ROOTMUTEX(); return (0); } SYSCTL_PROC(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW, NULL, 0, sysctl_dolocallocks, "IU", "Enable nfsd to acquire local locks on files"); #define MAX_REORDERED_RPC 16 #define NUM_HEURISTIC 1031 #define NHUSE_INIT 64 #define NHUSE_INC 16 #define NHUSE_MAX 2048 static struct nfsheur { struct vnode *nh_vp; /* vp to match (unreferenced pointer) */ off_t nh_nextoff; /* next offset for sequential detection */ int nh_use; /* use count for selection */ int nh_seqcount; /* heuristic */ } nfsheur[NUM_HEURISTIC]; /* * Heuristic to detect sequential operation. */ static struct nfsheur * nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp) { struct nfsheur *nh; int hi, try; /* Locate best candidate. */ try = 32; hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC; nh = &nfsheur[hi]; while (try--) { if (nfsheur[hi].nh_vp == vp) { nh = &nfsheur[hi]; break; } if (nfsheur[hi].nh_use > 0) --nfsheur[hi].nh_use; hi = (hi + 1) % NUM_HEURISTIC; if (nfsheur[hi].nh_use < nh->nh_use) nh = &nfsheur[hi]; } /* Initialize hint if this is a new file. */ if (nh->nh_vp != vp) { nh->nh_vp = vp; nh->nh_nextoff = uio->uio_offset; nh->nh_use = NHUSE_INIT; if (uio->uio_offset == 0) nh->nh_seqcount = 4; else nh->nh_seqcount = 1; } /* Calculate heuristic. */ if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) || uio->uio_offset == nh->nh_nextoff) { /* See comments in vfs_vnops.c:sequential_heuristic(). */ nh->nh_seqcount += howmany(uio->uio_resid, 16384); if (nh->nh_seqcount > IO_SEQMAX) nh->nh_seqcount = IO_SEQMAX; } else if (qabs(uio->uio_offset - nh->nh_nextoff) <= MAX_REORDERED_RPC * imax(vp->v_mount->mnt_stat.f_iosize, uio->uio_resid)) { /* Probably a reordered RPC, leave seqcount alone. */ } else if (nh->nh_seqcount > 1) { nh->nh_seqcount /= 2; } else { nh->nh_seqcount = 0; } nh->nh_use += NHUSE_INC; if (nh->nh_use > NHUSE_MAX) nh->nh_use = NHUSE_MAX; return (nh); } /* * Get attributes into nfsvattr structure. */ int nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap, struct nfsrv_descript *nd, struct thread *p, int vpislocked, nfsattrbit_t *attrbitp) { int error, gotattr, lockedit = 0; struct nfsvattr na; if (vpislocked == 0) { /* * When vpislocked == 0, the vnode is either exclusively * locked by this thread or not locked by this thread. * As such, shared lock it, if not exclusively locked. */ if (NFSVOPISLOCKED(vp) != LK_EXCLUSIVE) { lockedit = 1; NFSVOPLOCK(vp, LK_SHARED | LK_RETRY); } } /* * Acquire the Change, Size, TimeAccess, TimeModify and SpaceUsed * attributes, as required. * This needs to be done for regular files if: * - non-NFSv4 RPCs or * - when attrbitp == NULL or * - an NFSv4 RPC with any of the above attributes in attrbitp. * A return of 0 for nfsrv_proxyds() indicates that it has acquired * these attributes. nfsrv_proxyds() will return an error if the * server is not a pNFS one. */ gotattr = 0; if (vp->v_type == VREG && nfsrv_devidcnt > 0 && (attrbitp == NULL || (nd->nd_flag & ND_NFSV4) == 0 || NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_CHANGE) || NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE) || NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEACCESS) || NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEMODIFY) || NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SPACEUSED))) { error = nfsrv_proxyds(vp, 0, 0, nd->nd_cred, p, NFSPROC_GETATTR, NULL, NULL, NULL, &na, NULL, NULL, 0, NULL); if (error == 0) gotattr = 1; } nvap->na_bsdflags = 0; nvap->na_flags = 0; error = VOP_GETATTR(vp, &nvap->na_vattr, nd->nd_cred); if (lockedit != 0) NFSVOPUNLOCK(vp); /* * If we got the Change, Size and Modify Time from the DS, * replace them. */ if (gotattr != 0) { nvap->na_atime = na.na_atime; nvap->na_mtime = na.na_mtime; nvap->na_filerev = na.na_filerev; nvap->na_size = na.na_size; nvap->na_bytes = na.na_bytes; } NFSD_DEBUG(4, "nfsvno_getattr: gotattr=%d err=%d chg=%ju\n", gotattr, error, (uintmax_t)na.na_filerev); NFSEXITCODE(error); return (error); } /* * Get a file handle for a vnode. */ int nfsvno_getfh(struct vnode *vp, fhandle_t *fhp, struct thread *p) { int error; NFSBZERO((caddr_t)fhp, sizeof(fhandle_t)); fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; error = VOP_VPTOFH(vp, &fhp->fh_fid); NFSEXITCODE(error); return (error); } /* * Perform access checking for vnodes obtained from file handles that would * refer to files already opened by a Unix client. You cannot just use * vn_writechk() and VOP_ACCESSX() for two reasons. * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write * case. * 2 - The owner is to be given access irrespective of mode bits for some * operations, so that processes that chmod after opening a file don't * break. */ int nfsvno_accchk(struct vnode *vp, accmode_t accmode, struct ucred *cred, struct nfsexstuff *exp, struct thread *p, int override, int vpislocked, u_int32_t *supportedtypep) { struct vattr vattr; int error = 0, getret = 0; if (vpislocked == 0) { if (NFSVOPLOCK(vp, LK_SHARED) != 0) { error = EPERM; goto out; } } if (accmode & VWRITE) { /* Just vn_writechk() changed to check rdonly */ /* * Disallow write attempts on read-only file systems; * unless the file is a socket or a block or character * device resident on the file system. */ if (NFSVNO_EXRDONLY(exp) || (vp->v_mount->mnt_flag & MNT_RDONLY)) { switch (vp->v_type) { case VREG: case VDIR: case VLNK: error = EROFS; default: break; } } /* * If there's shared text associated with * the inode, try to free it up once. If * we fail, we can't allow writing. */ if (VOP_IS_TEXT(vp) && error == 0) error = ETXTBSY; } if (error != 0) { if (vpislocked == 0) NFSVOPUNLOCK(vp); goto out; } /* * Should the override still be applied when ACLs are enabled? */ error = VOP_ACCESSX(vp, accmode, cred, p); if (error != 0 && (accmode & (VDELETE | VDELETE_CHILD))) { /* * Try again with VEXPLICIT_DENY, to see if the test for * deletion is supported. */ error = VOP_ACCESSX(vp, accmode | VEXPLICIT_DENY, cred, p); if (error == 0) { if (vp->v_type == VDIR) { accmode &= ~(VDELETE | VDELETE_CHILD); accmode |= VWRITE; error = VOP_ACCESSX(vp, accmode, cred, p); } else if (supportedtypep != NULL) { *supportedtypep &= ~NFSACCESS_DELETE; } } } /* * Allow certain operations for the owner (reads and writes * on files that are already open). */ if (override != NFSACCCHK_NOOVERRIDE && (error == EPERM || error == EACCES)) { if (cred->cr_uid == 0 && (override & NFSACCCHK_ALLOWROOT)) error = 0; else if (override & NFSACCCHK_ALLOWOWNER) { getret = VOP_GETATTR(vp, &vattr, cred); if (getret == 0 && cred->cr_uid == vattr.va_uid) error = 0; } } if (vpislocked == 0) NFSVOPUNLOCK(vp); out: NFSEXITCODE(error); return (error); } /* * Set attribute(s) vnop. */ int nfsvno_setattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred, struct thread *p, struct nfsexstuff *exp) { u_quad_t savsize = 0; int error, savedit; time_t savbtime; /* * If this is an exported file system and a pNFS service is running, * don't VOP_SETATTR() of size for the MDS file system. */ savedit = 0; error = 0; if (vp->v_type == VREG && (vp->v_mount->mnt_flag & MNT_EXPORTED) != 0 && nfsrv_devidcnt != 0 && nvap->na_vattr.va_size != VNOVAL && nvap->na_vattr.va_size > 0) { savsize = nvap->na_vattr.va_size; nvap->na_vattr.va_size = VNOVAL; if (nvap->na_vattr.va_uid != (uid_t)VNOVAL || nvap->na_vattr.va_gid != (gid_t)VNOVAL || nvap->na_vattr.va_mode != (mode_t)VNOVAL || nvap->na_vattr.va_atime.tv_sec != VNOVAL || nvap->na_vattr.va_mtime.tv_sec != VNOVAL) savedit = 1; else savedit = 2; } if (savedit != 2) error = VOP_SETATTR(vp, &nvap->na_vattr, cred); if (savedit != 0) nvap->na_vattr.va_size = savsize; if (error == 0 && (nvap->na_vattr.va_uid != (uid_t)VNOVAL || nvap->na_vattr.va_gid != (gid_t)VNOVAL || nvap->na_vattr.va_size != VNOVAL || nvap->na_vattr.va_mode != (mode_t)VNOVAL || nvap->na_vattr.va_atime.tv_sec != VNOVAL || nvap->na_vattr.va_mtime.tv_sec != VNOVAL)) { /* Never modify birthtime on a DS file. */ savbtime = nvap->na_vattr.va_birthtime.tv_sec; nvap->na_vattr.va_birthtime.tv_sec = VNOVAL; /* For a pNFS server, set the attributes on the DS file. */ error = nfsrv_proxyds(vp, 0, 0, cred, p, NFSPROC_SETATTR, NULL, NULL, NULL, nvap, NULL, NULL, 0, NULL); nvap->na_vattr.va_birthtime.tv_sec = savbtime; if (error == ENOENT) error = 0; } NFSEXITCODE(error); return (error); } /* * Set up nameidata for a lookup() call and do it. */ int nfsvno_namei(struct nfsrv_descript *nd, struct nameidata *ndp, struct vnode *dp, int islocked, struct nfsexstuff *exp, struct vnode **retdirp) { struct componentname *cnp = &ndp->ni_cnd; int i; struct iovec aiov; struct uio auio; int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0, linklen; int error = 0; char *cp; *retdirp = NULL; cnp->cn_nameptr = cnp->cn_pnbuf; ndp->ni_lcf = 0; /* * Extract and set starting directory. */ if (dp->v_type != VDIR) { if (islocked) vput(dp); else vrele(dp); nfsvno_relpathbuf(ndp); error = ENOTDIR; goto out1; } if (islocked) NFSVOPUNLOCK(dp); - VREF(dp); + vref(dp); *retdirp = dp; if (NFSVNO_EXRDONLY(exp)) cnp->cn_flags |= RDONLY; ndp->ni_segflg = UIO_SYSSPACE; if (nd->nd_flag & ND_PUBLOOKUP) { ndp->ni_loopcnt = 0; if (cnp->cn_pnbuf[0] == '/') { vrele(dp); /* * Check for degenerate pathnames here, since lookup() * panics on them. */ for (i = 1; i < ndp->ni_pathlen; i++) if (cnp->cn_pnbuf[i] != '/') break; if (i == ndp->ni_pathlen) { error = NFSERR_ACCES; goto out; } dp = rootvnode; - VREF(dp); + vref(dp); } } else if ((nfsrv_enable_crossmntpt == 0 && NFSVNO_EXPORTED(exp)) || (nd->nd_flag & ND_NFSV4) == 0) { /* * Only cross mount points for NFSv4 when doing a * mount while traversing the file system above * the mount point, unless nfsrv_enable_crossmntpt is set. */ cnp->cn_flags |= NOCROSSMOUNT; } /* * Initialize for scan, set ni_startdir and bump ref on dp again * because lookup() will dereference ni_startdir. */ ndp->ni_startdir = dp; ndp->ni_rootdir = rootvnode; ndp->ni_topdir = NULL; if (!lockleaf) cnp->cn_flags |= LOCKLEAF; for (;;) { cnp->cn_nameptr = cnp->cn_pnbuf; /* * Call lookup() to do the real work. If an error occurs, * ndp->ni_vp and ni_dvp are left uninitialized or NULL and * we do not have to dereference anything before returning. * In either case ni_startdir will be dereferenced and NULLed * out. */ error = vfs_lookup(ndp); if (error) break; /* * Check for encountering a symbolic link. Trivial * termination occurs if no symlink encountered. */ if ((cnp->cn_flags & ISSYMLINK) == 0) { if (ndp->ni_vp && !lockleaf) NFSVOPUNLOCK(ndp->ni_vp); break; } /* * Validate symlink */ if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) NFSVOPUNLOCK(ndp->ni_dvp); if (!(nd->nd_flag & ND_PUBLOOKUP)) { error = EINVAL; goto badlink2; } if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { error = ELOOP; goto badlink2; } if (ndp->ni_pathlen > 1) cp = uma_zalloc(namei_zone, M_WAITOK); else cp = cnp->cn_pnbuf; aiov.iov_base = cp; aiov.iov_len = MAXPATHLEN; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_SYSSPACE; auio.uio_td = NULL; auio.uio_resid = MAXPATHLEN; error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); if (error) { badlink1: if (ndp->ni_pathlen > 1) uma_zfree(namei_zone, cp); badlink2: vrele(ndp->ni_dvp); vput(ndp->ni_vp); break; } linklen = MAXPATHLEN - auio.uio_resid; if (linklen == 0) { error = ENOENT; goto badlink1; } if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { error = ENAMETOOLONG; goto badlink1; } /* * Adjust or replace path */ if (ndp->ni_pathlen > 1) { NFSBCOPY(ndp->ni_next, cp + linklen, ndp->ni_pathlen); uma_zfree(namei_zone, cnp->cn_pnbuf); cnp->cn_pnbuf = cp; } else cnp->cn_pnbuf[linklen] = '\0'; ndp->ni_pathlen += linklen; /* * Cleanup refs for next loop and check if root directory * should replace current directory. Normally ni_dvp * becomes the new base directory and is cleaned up when * we loop. Explicitly null pointers after invalidation * to clarify operation. */ vput(ndp->ni_vp); ndp->ni_vp = NULL; if (cnp->cn_pnbuf[0] == '/') { vrele(ndp->ni_dvp); ndp->ni_dvp = ndp->ni_rootdir; - VREF(ndp->ni_dvp); + vref(ndp->ni_dvp); } ndp->ni_startdir = ndp->ni_dvp; ndp->ni_dvp = NULL; } if (!lockleaf) cnp->cn_flags &= ~LOCKLEAF; out: if (error) { nfsvno_relpathbuf(ndp); ndp->ni_vp = NULL; ndp->ni_dvp = NULL; ndp->ni_startdir = NULL; } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { ndp->ni_dvp = NULL; } out1: NFSEXITCODE2(error, nd); return (error); } /* * Set up a pathname buffer and return a pointer to it and, optionally * set a hash pointer. */ void nfsvno_setpathbuf(struct nameidata *ndp, char **bufpp, u_long **hashpp) { struct componentname *cnp = &ndp->ni_cnd; cnp->cn_flags |= (NOMACCHECK); cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); if (hashpp != NULL) *hashpp = NULL; *bufpp = cnp->cn_pnbuf; } /* * Release the above path buffer, if not released by nfsvno_namei(). */ void nfsvno_relpathbuf(struct nameidata *ndp) { uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf); ndp->ni_cnd.cn_pnbuf = NULL; } /* * Readlink vnode op into an mbuf list. */ int nfsvno_readlink(struct vnode *vp, struct ucred *cred, int maxextsiz, struct thread *p, struct mbuf **mpp, struct mbuf **mpendp, int *lenp) { struct iovec *iv; struct uio io, *uiop = &io; struct mbuf *mp, *mp3; int len, tlen, error = 0; len = NFS_MAXPATHLEN; if (maxextsiz > 0) uiop->uio_iovcnt = nfsrv_createiovec_extpgs(len, maxextsiz, &mp3, &mp, &iv); else uiop->uio_iovcnt = nfsrv_createiovec(len, &mp3, &mp, &iv); uiop->uio_iov = iv; uiop->uio_offset = 0; uiop->uio_resid = len; uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_td = NULL; error = VOP_READLINK(vp, uiop, cred); free(iv, M_TEMP); if (error) { m_freem(mp3); *lenp = 0; goto out; } if (uiop->uio_resid > 0) { len -= uiop->uio_resid; tlen = NFSM_RNDUP(len); if (tlen == 0) { m_freem(mp3); mp3 = mp = NULL; } else if (tlen != NFS_MAXPATHLEN || tlen != len) mp = nfsrv_adj(mp3, NFS_MAXPATHLEN - tlen, tlen - len); } *lenp = len; *mpp = mp3; *mpendp = mp; out: NFSEXITCODE(error); return (error); } /* * Create an mbuf chain and an associated iovec that can be used to Read * or Getextattr of data. * Upon success, return pointers to the first and last mbufs in the chain * plus the malloc'd iovec and its iovlen. */ static int nfsrv_createiovec(int len, struct mbuf **mpp, struct mbuf **mpendp, struct iovec **ivp) { struct mbuf *m, *m2 = NULL, *m3; struct iovec *iv; int i, left, siz; left = len; m3 = NULL; /* * Generate the mbuf list with the uio_iov ref. to it. */ i = 0; while (left > 0) { NFSMGET(m); MCLGET(m, M_WAITOK); m->m_len = 0; siz = min(M_TRAILINGSPACE(m), left); left -= siz; i++; if (m3) m2->m_next = m; else m3 = m; m2 = m; } *ivp = iv = malloc(i * sizeof (struct iovec), M_TEMP, M_WAITOK); m = m3; left = len; i = 0; while (left > 0) { if (m == NULL) panic("nfsrv_createiovec iov"); siz = min(M_TRAILINGSPACE(m), left); if (siz > 0) { iv->iov_base = mtod(m, caddr_t) + m->m_len; iv->iov_len = siz; m->m_len += siz; left -= siz; iv++; i++; } m = m->m_next; } *mpp = m3; *mpendp = m2; return (i); } /* * Create an mbuf chain and an associated iovec that can be used to Read * or Getextattr of data. * Upon success, return pointers to the first and last mbufs in the chain * plus the malloc'd iovec and its iovlen. * Same as above, but creates ext_pgs mbuf(s). */ static int nfsrv_createiovec_extpgs(int len, int maxextsiz, struct mbuf **mpp, struct mbuf **mpendp, struct iovec **ivp) { struct mbuf *m, *m2 = NULL, *m3; struct iovec *iv; int i, left, pgno, siz; left = len; m3 = NULL; /* * Generate the mbuf list with the uio_iov ref. to it. */ i = 0; while (left > 0) { siz = min(left, maxextsiz); m = mb_alloc_ext_plus_pages(siz, M_WAITOK); left -= siz; i += m->m_epg_npgs; if (m3 != NULL) m2->m_next = m; else m3 = m; m2 = m; } *ivp = iv = malloc(i * sizeof (struct iovec), M_TEMP, M_WAITOK); m = m3; left = len; i = 0; pgno = 0; while (left > 0) { if (m == NULL) panic("nfsvno_createiovec_extpgs iov"); siz = min(PAGE_SIZE, left); if (siz > 0) { iv->iov_base = (void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]); iv->iov_len = siz; m->m_len += siz; if (pgno == m->m_epg_npgs - 1) m->m_epg_last_len = siz; left -= siz; iv++; i++; pgno++; } if (pgno == m->m_epg_npgs && left > 0) { m = m->m_next; if (m == NULL) panic("nfsvno_createiovec_extpgs iov"); pgno = 0; } } *mpp = m3; *mpendp = m2; return (i); } /* * Read vnode op call into mbuf list. */ int nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred, int maxextsiz, struct thread *p, struct mbuf **mpp, struct mbuf **mpendp) { struct mbuf *m; struct iovec *iv; int error = 0, len, tlen, ioflag = 0; struct mbuf *m3; struct uio io, *uiop = &io; struct nfsheur *nh; /* * Attempt to read from a DS file. A return of ENOENT implies * there is no DS file to read. */ error = nfsrv_proxyds(vp, off, cnt, cred, p, NFSPROC_READDS, mpp, NULL, mpendp, NULL, NULL, NULL, 0, NULL); if (error != ENOENT) return (error); len = NFSM_RNDUP(cnt); if (maxextsiz > 0) uiop->uio_iovcnt = nfsrv_createiovec_extpgs(len, maxextsiz, &m3, &m, &iv); else uiop->uio_iovcnt = nfsrv_createiovec(len, &m3, &m, &iv); uiop->uio_iov = iv; uiop->uio_offset = off; uiop->uio_resid = len; uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_td = NULL; nh = nfsrv_sequential_heuristic(uiop, vp); ioflag |= nh->nh_seqcount << IO_SEQSHIFT; /* XXX KDM make this more systematic? */ NFSD_VNET(nfsstatsv1_p)->srvbytes[NFSV4OP_READ] += uiop->uio_resid; error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred); free(iv, M_TEMP); if (error) { m_freem(m3); *mpp = NULL; goto out; } nh->nh_nextoff = uiop->uio_offset; tlen = len - uiop->uio_resid; cnt = cnt < tlen ? cnt : tlen; tlen = NFSM_RNDUP(cnt); if (tlen == 0) { m_freem(m3); m3 = m = NULL; } else if (len != tlen || tlen != cnt) m = nfsrv_adj(m3, len - tlen, tlen - cnt); *mpp = m3; *mpendp = m; out: NFSEXITCODE(error); return (error); } /* * Create the iovec for the mbuf chain passed in as an argument. * The "cp" argument is where the data starts within the first mbuf in * the chain. It returns the iovec and the iovcnt. */ static int nfsrv_createiovecw(int retlen, struct mbuf *m, char *cp, struct iovec **ivpp, int *iovcntp) { struct mbuf *mp; struct iovec *ivp; int cnt, i, len; /* * Loop through the mbuf chain, counting how many mbufs are a * part of this write operation, so the iovec size is known. */ cnt = 0; len = retlen; mp = m; i = mtod(mp, caddr_t) + mp->m_len - cp; while (len > 0) { if (i > 0) { len -= i; cnt++; } mp = mp->m_next; if (!mp) { if (len > 0) return (EBADRPC); } else i = mp->m_len; } /* Now, create the iovec. */ mp = m; *ivpp = ivp = malloc(cnt * sizeof (struct iovec), M_TEMP, M_WAITOK); *iovcntp = cnt; i = mtod(mp, caddr_t) + mp->m_len - cp; len = retlen; while (len > 0) { if (mp == NULL) panic("nfsrv_createiovecw"); if (i > 0) { i = min(i, len); ivp->iov_base = cp; ivp->iov_len = i; ivp++; len -= i; } mp = mp->m_next; if (mp) { i = mp->m_len; cp = mtod(mp, caddr_t); } } return (0); } /* * Write vnode op from an mbuf list. */ int nfsvno_write(struct vnode *vp, off_t off, int retlen, int *stable, struct mbuf *mp, char *cp, struct ucred *cred, struct thread *p) { struct iovec *iv; int cnt, ioflags, error; struct uio io, *uiop = &io; struct nfsheur *nh; /* * Attempt to write to a DS file. A return of ENOENT implies * there is no DS file to write. */ error = nfsrv_proxyds(vp, off, retlen, cred, p, NFSPROC_WRITEDS, &mp, cp, NULL, NULL, NULL, NULL, 0, NULL); if (error != ENOENT) { *stable = NFSWRITE_FILESYNC; return (error); } if (*stable == NFSWRITE_UNSTABLE) ioflags = IO_NODELOCKED; else ioflags = (IO_SYNC | IO_NODELOCKED); error = nfsrv_createiovecw(retlen, mp, cp, &iv, &cnt); if (error != 0) return (error); uiop->uio_iov = iv; uiop->uio_iovcnt = cnt; uiop->uio_resid = retlen; uiop->uio_rw = UIO_WRITE; uiop->uio_segflg = UIO_SYSSPACE; NFSUIOPROC(uiop, p); uiop->uio_offset = off; nh = nfsrv_sequential_heuristic(uiop, vp); ioflags |= nh->nh_seqcount << IO_SEQSHIFT; /* XXX KDM make this more systematic? */ NFSD_VNET(nfsstatsv1_p)->srvbytes[NFSV4OP_WRITE] += uiop->uio_resid; error = VOP_WRITE(vp, uiop, ioflags, cred); if (error == 0) nh->nh_nextoff = uiop->uio_offset; free(iv, M_TEMP); NFSEXITCODE(error); return (error); } /* * Common code for creating a regular file (plus special files for V2). */ int nfsvno_createsub(struct nfsrv_descript *nd, struct nameidata *ndp, struct vnode **vpp, struct nfsvattr *nvap, int *exclusive_flagp, int32_t *cverf, NFSDEV_T rdev, struct nfsexstuff *exp) { u_quad_t tempsize; int error; struct thread *p = curthread; error = nd->nd_repstat; if (!error && ndp->ni_vp == NULL) { if (nvap->na_type == VREG || nvap->na_type == VSOCK) { error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr); /* For a pNFS server, create the data file on a DS. */ if (error == 0 && nvap->na_type == VREG) { /* * Create a data file on a DS for a pNFS server. * This function just returns if not * running a pNFS DS or the creation fails. */ nfsrv_pnfscreate(ndp->ni_vp, &nvap->na_vattr, nd->nd_cred, p); } VOP_VPUT_PAIR(ndp->ni_dvp, error == 0 ? &ndp->ni_vp : NULL, false); nfsvno_relpathbuf(ndp); if (!error) { if (*exclusive_flagp) { *exclusive_flagp = 0; NFSVNO_ATTRINIT(nvap); nvap->na_atime.tv_sec = cverf[0]; nvap->na_atime.tv_nsec = cverf[1]; error = VOP_SETATTR(ndp->ni_vp, &nvap->na_vattr, nd->nd_cred); if (error != 0) { vput(ndp->ni_vp); ndp->ni_vp = NULL; error = NFSERR_NOTSUPP; } } } /* * NFS V2 Only. nfsrvd_mknod() does this for V3. * (This implies, just get out on an error.) */ } else if (nvap->na_type == VCHR || nvap->na_type == VBLK || nvap->na_type == VFIFO) { if (nvap->na_type == VCHR && rdev == 0xffffffff) nvap->na_type = VFIFO; if (nvap->na_type != VFIFO && (error = priv_check_cred(nd->nd_cred, PRIV_VFS_MKNOD_DEV))) { nfsvno_relpathbuf(ndp); vput(ndp->ni_dvp); goto out; } nvap->na_rdev = rdev; error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr); VOP_VPUT_PAIR(ndp->ni_dvp, error == 0 ? &ndp->ni_vp : NULL, false); nfsvno_relpathbuf(ndp); if (error) goto out; } else { nfsvno_relpathbuf(ndp); vput(ndp->ni_dvp); error = ENXIO; goto out; } *vpp = ndp->ni_vp; } else { /* * Handle cases where error is already set and/or * the file exists. * 1 - clean up the lookup * 2 - iff !error and na_size set, truncate it */ nfsvno_relpathbuf(ndp); *vpp = ndp->ni_vp; if (ndp->ni_dvp == *vpp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); if (!error && nvap->na_size != VNOVAL) { error = nfsvno_accchk(*vpp, VWRITE, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, NULL); if (!error) { tempsize = nvap->na_size; NFSVNO_ATTRINIT(nvap); nvap->na_size = tempsize; error = nfsvno_setattr(*vpp, nvap, nd->nd_cred, p, exp); } } if (error) vput(*vpp); } out: NFSEXITCODE(error); return (error); } /* * Do a mknod vnode op. */ int nfsvno_mknod(struct nameidata *ndp, struct nfsvattr *nvap, struct ucred *cred, struct thread *p) { int error = 0; __enum_uint8(vtype) vtyp; vtyp = nvap->na_type; /* * Iff doesn't exist, create it. */ if (ndp->ni_vp) { nfsvno_relpathbuf(ndp); vput(ndp->ni_dvp); vrele(ndp->ni_vp); error = EEXIST; goto out; } if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { nfsvno_relpathbuf(ndp); vput(ndp->ni_dvp); error = NFSERR_BADTYPE; goto out; } if (vtyp == VSOCK) { error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr); VOP_VPUT_PAIR(ndp->ni_dvp, error == 0 ? &ndp->ni_vp : NULL, false); nfsvno_relpathbuf(ndp); } else { if (nvap->na_type != VFIFO && (error = priv_check_cred(cred, PRIV_VFS_MKNOD_DEV))) { nfsvno_relpathbuf(ndp); vput(ndp->ni_dvp); goto out; } error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr); VOP_VPUT_PAIR(ndp->ni_dvp, error == 0 ? &ndp->ni_vp : NULL, false); nfsvno_relpathbuf(ndp); /* * Since VOP_MKNOD returns the ni_vp, I can't * see any reason to do the lookup. */ } out: NFSEXITCODE(error); return (error); } /* * Mkdir vnode op. */ int nfsvno_mkdir(struct nameidata *ndp, struct nfsvattr *nvap, uid_t saved_uid, struct ucred *cred, struct thread *p, struct nfsexstuff *exp) { int error = 0; if (ndp->ni_vp != NULL) { if (ndp->ni_dvp == ndp->ni_vp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); vrele(ndp->ni_vp); nfsvno_relpathbuf(ndp); error = EEXIST; goto out; } error = VOP_MKDIR(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr); VOP_VPUT_PAIR(ndp->ni_dvp, error == 0 ? &ndp->ni_vp : NULL, false); nfsvno_relpathbuf(ndp); out: NFSEXITCODE(error); return (error); } /* * symlink vnode op. */ int nfsvno_symlink(struct nameidata *ndp, struct nfsvattr *nvap, char *pathcp, int pathlen, int not_v2, uid_t saved_uid, struct ucred *cred, struct thread *p, struct nfsexstuff *exp) { int error = 0; if (ndp->ni_vp) { nfsvno_relpathbuf(ndp); if (ndp->ni_dvp == ndp->ni_vp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); vrele(ndp->ni_vp); error = EEXIST; goto out; } error = VOP_SYMLINK(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr, pathcp); /* * Although FreeBSD still had the lookup code in * it for 7/current, there doesn't seem to be any * point, since VOP_SYMLINK() returns the ni_vp. * Just vput it for v2. */ VOP_VPUT_PAIR(ndp->ni_dvp, &ndp->ni_vp, !not_v2 && error == 0); nfsvno_relpathbuf(ndp); out: NFSEXITCODE(error); return (error); } /* * Parse symbolic link arguments. * This function has an ugly side effect. It will malloc() an area for * the symlink and set iov_base to point to it, only if it succeeds. * So, if it returns with uiop->uio_iov->iov_base != NULL, that must * be FREE'd later. */ int nfsvno_getsymlink(struct nfsrv_descript *nd, struct nfsvattr *nvap, struct thread *p, char **pathcpp, int *lenp) { u_int32_t *tl; char *pathcp = NULL; int error = 0, len; struct nfsv2_sattr *sp; *pathcpp = NULL; *lenp = 0; if ((nd->nd_flag & ND_NFSV3) && (error = nfsrv_sattr(nd, NULL, nvap, NULL, NULL, p))) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(int, *tl); if (len > NFS_MAXPATHLEN || len <= 0) { error = EBADRPC; goto nfsmout; } pathcp = malloc(len + 1, M_TEMP, M_WAITOK); error = nfsrv_mtostr(nd, pathcp, len); if (error) goto nfsmout; if (nd->nd_flag & ND_NFSV2) { NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); nvap->na_mode = fxdr_unsigned(u_int16_t, sp->sa_mode); } *pathcpp = pathcp; *lenp = len; NFSEXITCODE2(0, nd); return (0); nfsmout: if (pathcp) free(pathcp, M_TEMP); NFSEXITCODE2(error, nd); return (error); } /* * Remove a non-directory object. */ int nfsvno_removesub(struct nameidata *ndp, bool is_v4, struct nfsrv_descript *nd, struct thread *p, struct nfsexstuff *exp) { struct vnode *vp, *dsdvp[NFSDEV_MAXMIRRORS], *newvp; struct mount *mp; int error = 0, mirrorcnt, ret; char fname[PNFS_FILENAME_LEN + 1]; fhandle_t fh; vp = ndp->ni_vp; dsdvp[0] = NULL; if (vp->v_type == VDIR) { error = NFSERR_ISDIR; } else if (is_v4) { if (nfsrv_recalldeleg || (nd->nd_flag & ND_NFSV41) == 0) error = nfsrv_checkremove(vp, 1, NULL, (nfsquad_t)((u_quad_t)0), p); else error = nfsrv_checkremove(vp, 1, NULL, nd->nd_clientid, p); } if (error == 0) nfsrv_pnfsremovesetup(vp, p, dsdvp, &mirrorcnt, fname, &fh); if (!error) error = VOP_REMOVE(ndp->ni_dvp, vp, &ndp->ni_cnd); if (error == 0 && dsdvp[0] != NULL) nfsrv_pnfsremove(dsdvp, mirrorcnt, fname, &fh, p); if (is_v4 && (nd->nd_flag & ND_NFSV41) != 0 && error == 0) error = nfsvno_getfh(vp, &fh, p); if (ndp->ni_dvp == vp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); vput(vp); /* Use ret to determine if the file still exists. */ if (is_v4 && (nd->nd_flag & ND_NFSV41) != 0 && error == 0) { mp = vfs_busyfs(&fh.fh_fsid); if (mp != NULL) { /* Find out if the file still exists. */ ret = VFS_FHTOVP(mp, &fh.fh_fid, LK_SHARED, &newvp); if (ret == 0) vput(newvp); else ret = ESTALE; vfs_unbusy(mp); } else { ret = ESTALE; } if (ret == ESTALE) { /* Get rid of any delegation. */ nfsrv_removedeleg(&fh, nd, p); } } nfsvno_relpathbuf(ndp); NFSEXITCODE(error); return (error); } /* * Remove a directory. */ int nfsvno_rmdirsub(struct nameidata *ndp, int is_v4, struct ucred *cred, struct thread *p, struct nfsexstuff *exp) { struct vnode *vp; int error = 0; vp = ndp->ni_vp; if (vp->v_type != VDIR) { error = ENOTDIR; goto out; } /* * No rmdir "." please. */ if (ndp->ni_dvp == vp) { error = EINVAL; goto out; } /* * The root of a mounted filesystem cannot be deleted. */ if (vp->v_vflag & VV_ROOT) error = EBUSY; out: if (!error) error = VOP_RMDIR(ndp->ni_dvp, vp, &ndp->ni_cnd); if (ndp->ni_dvp == vp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); vput(vp); nfsvno_relpathbuf(ndp); NFSEXITCODE(error); return (error); } /* * Rename vnode op. */ int nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp, struct nfsrv_descript *nd, struct thread *p) { struct vnode *fvp, *tvp, *tdvp, *dsdvp[NFSDEV_MAXMIRRORS], *newvp; struct mount *mp; int error = 0, mirrorcnt, ret; char fname[PNFS_FILENAME_LEN + 1]; fhandle_t fh, fh2; dsdvp[0] = NULL; fvp = fromndp->ni_vp; if (nd->nd_repstat != 0) { vrele(fromndp->ni_dvp); vrele(fvp); error = nd->nd_repstat; goto out1; } tdvp = tondp->ni_dvp; tvp = tondp->ni_vp; if (tvp != NULL) { if (fvp->v_type == VDIR && tvp->v_type != VDIR) { error = (nd->nd_flag & ND_NFSV2) ? EISDIR : EEXIST; goto out; } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { error = (nd->nd_flag & ND_NFSV2) ? ENOTDIR : EEXIST; goto out; } if (tvp->v_type == VDIR && tvp->v_mountedhere) { error = (nd->nd_flag & ND_NFSV2) ? ENOTEMPTY : EXDEV; goto out; } /* * A rename to '.' or '..' results in a prematurely * unlocked vnode on FreeBSD5, so I'm just going to fail that * here. */ if ((tondp->ni_cnd.cn_namelen == 1 && tondp->ni_cnd.cn_nameptr[0] == '.') || (tondp->ni_cnd.cn_namelen == 2 && tondp->ni_cnd.cn_nameptr[0] == '.' && tondp->ni_cnd.cn_nameptr[1] == '.')) { error = EINVAL; goto out; } } if (fvp->v_type == VDIR && fvp->v_mountedhere) { error = (nd->nd_flag & ND_NFSV2) ? ENOTEMPTY : EXDEV; goto out; } if (fvp->v_mount != tdvp->v_mount) { error = (nd->nd_flag & ND_NFSV2) ? ENOTEMPTY : EXDEV; goto out; } if (fvp == tdvp) { error = (nd->nd_flag & ND_NFSV2) ? ENOTEMPTY : EINVAL; goto out; } if (fvp == tvp) { /* * If source and destination are the same, there is * nothing to do. Set error to EJUSTRETURN to indicate * this. */ error = EJUSTRETURN; goto out; } if (nd->nd_flag & ND_NFSV4) { if (NFSVOPLOCK(fvp, LK_EXCLUSIVE) == 0) { if (nfsrv_recalldeleg || (nd->nd_flag & ND_NFSV41) == 0) error = nfsrv_checkremove(fvp, 0, NULL, (nfsquad_t)((u_quad_t)0), p); else error = nfsrv_checkremove(fvp, 0, NULL, nd->nd_clientid, p); NFSVOPUNLOCK(fvp); } else error = EPERM; if (tvp && !error) { if (nfsrv_recalldeleg || (nd->nd_flag & ND_NFSV41) == 0) error = nfsrv_checkremove(tvp, 1, NULL, (nfsquad_t)((u_quad_t)0), p); else error = nfsrv_checkremove(tvp, 1, NULL, nd->nd_clientid, p); } } else { /* * For NFSv2 and NFSv3, try to get rid of the delegation, so * that the NFSv4 client won't be confused by the rename. * Since nfsd_recalldelegation() can only be called on an * unlocked vnode at this point and fvp is the file that will * still exist after the rename, just do fvp. */ nfsd_recalldelegation(fvp, p); } if (error == 0 && tvp != NULL) { if ((nd->nd_flag & ND_NFSV41) != 0) error = nfsvno_getfh(tvp, &fh2, p); if (error == 0) nfsrv_pnfsremovesetup(tvp, p, dsdvp, &mirrorcnt, fname, &fh); NFSD_DEBUG(4, "nfsvno_rename: pnfsremovesetup" " dsdvp=%p\n", dsdvp[0]); } out: mp = NULL; if (error == 0) { error = VOP_GETWRITEMOUNT(tondp->ni_dvp, &mp); if (error == 0) { if (mp == NULL) { error = ENOENT; } else { error = lockmgr(&mp->mnt_renamelock, LK_EXCLUSIVE | LK_NOWAIT, NULL); if (error != 0) error = ERELOOKUP; } } } if (error == 0) { error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp, &fromndp->ni_cnd, tondp->ni_dvp, tondp->ni_vp, &tondp->ni_cnd); lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0); vfs_rel(mp); } else { if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp) vput(tvp); vrele(fromndp->ni_dvp); vrele(fvp); if (error == EJUSTRETURN) { error = 0; } else if (error == ERELOOKUP && mp != NULL) { lockmgr(&mp->mnt_renamelock, LK_EXCLUSIVE, 0); lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0); vfs_rel(mp); } } /* * If dsdvp[0] != NULL, it was set up by nfsrv_pnfsremovesetup() and * if the rename succeeded, the DS file for the tvp needs to be * removed. */ if (error == 0 && dsdvp[0] != NULL) { nfsrv_pnfsremove(dsdvp, mirrorcnt, fname, &fh, p); NFSD_DEBUG(4, "nfsvno_rename: pnfsremove\n"); } /* Use ret to determine if the file still exists. */ if ((nd->nd_flag & ND_NFSV41) != 0 && error == 0) { mp = vfs_busyfs(&fh2.fh_fsid); if (mp != NULL) { /* Find out if the file still exists. */ ret = VFS_FHTOVP(mp, &fh2.fh_fid, LK_SHARED, &newvp); if (ret == 0) vput(newvp); else ret = ESTALE; vfs_unbusy(mp); } else { ret = ESTALE; } if (ret == ESTALE) { /* Get rid of any delegation. */ nfsrv_removedeleg(&fh2, nd, p); } } nfsvno_relpathbuf(tondp); out1: nfsvno_relpathbuf(fromndp); NFSEXITCODE(error); return (error); } /* * Link vnode op. */ int nfsvno_link(struct nameidata *ndp, struct vnode *vp, nfsquad_t clientid, struct ucred *cred, struct thread *p, struct nfsexstuff *exp) { struct vnode *xp; int error = 0; xp = ndp->ni_vp; if (xp != NULL) { error = EEXIST; } else { xp = ndp->ni_dvp; if (vp->v_mount != xp->v_mount) error = EXDEV; } if (!error) { NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); if (!VN_IS_DOOMED(vp)) { error = nfsrv_checkremove(vp, 0, NULL, clientid, p); if (error == 0) error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd); } else error = EPERM; if (ndp->ni_dvp == vp) { vrele(ndp->ni_dvp); NFSVOPUNLOCK(vp); } else { vref(vp); VOP_VPUT_PAIR(ndp->ni_dvp, &vp, true); } } else { if (ndp->ni_dvp == ndp->ni_vp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); if (ndp->ni_vp) vrele(ndp->ni_vp); } nfsvno_relpathbuf(ndp); NFSEXITCODE(error); return (error); } /* * Do the fsync() appropriate for the commit. */ int nfsvno_fsync(struct vnode *vp, u_int64_t off, int cnt, struct ucred *cred, struct thread *td) { int error = 0; /* * RFC 1813 3.3.21: if count is 0, a flush from offset to the end of * file is done. At this time VOP_FSYNC does not accept offset and * byte count parameters so call VOP_FSYNC the whole file for now. * The same is true for NFSv4: RFC 3530 Sec. 14.2.3. * File systems that do not use the buffer cache (as indicated * by MNTK_USES_BCACHE not being set) must use VOP_FSYNC(). */ if (cnt == 0 || cnt > MAX_COMMIT_COUNT || (vp->v_mount->mnt_kern_flag & MNTK_USES_BCACHE) == 0) { /* * Give up and do the whole thing */ vnode_pager_clean_sync(vp); error = VOP_FSYNC(vp, MNT_WAIT, td); } else { /* * Locate and synchronously write any buffers that fall * into the requested range. Note: we are assuming that * f_iosize is a power of 2. */ int iosize = vp->v_mount->mnt_stat.f_iosize; int iomask = iosize - 1; struct bufobj *bo; daddr_t lblkno; /* * Align to iosize boundary, super-align to page boundary. */ if (off & iomask) { cnt += off & iomask; off &= ~(u_quad_t)iomask; } if (off & PAGE_MASK) { cnt += off & PAGE_MASK; off &= ~(u_quad_t)PAGE_MASK; } lblkno = off / iosize; if (vp->v_object && vm_object_mightbedirty(vp->v_object)) { VM_OBJECT_WLOCK(vp->v_object); vm_object_page_clean(vp->v_object, off, off + cnt, OBJPC_SYNC); VM_OBJECT_WUNLOCK(vp->v_object); } bo = &vp->v_bufobj; BO_LOCK(bo); while (cnt > 0) { struct buf *bp; /* * If we have a buffer and it is marked B_DELWRI we * have to lock and write it. Otherwise the prior * write is assumed to have already been committed. * * gbincore() can return invalid buffers now so we * have to check that bit as well (though B_DELWRI * should not be set if B_INVAL is set there could be * a race here since we haven't locked the buffer). */ if ((bp = gbincore(&vp->v_bufobj, lblkno)) != NULL) { if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, BO_LOCKPTR(bo)) == ENOLCK) { BO_LOCK(bo); continue; /* retry */ } if ((bp->b_flags & (B_DELWRI|B_INVAL)) == B_DELWRI) { bremfree(bp); bp->b_flags &= ~B_ASYNC; bwrite(bp); ++nfs_commit_miss; } else BUF_UNLOCK(bp); BO_LOCK(bo); } ++nfs_commit_blks; if (cnt < iosize) break; cnt -= iosize; ++lblkno; } BO_UNLOCK(bo); } NFSEXITCODE(error); return (error); } /* * Statfs vnode op. */ int nfsvno_statfs(struct vnode *vp, struct statfs *sf) { struct statfs *tsf; int error; tsf = NULL; if (nfsrv_devidcnt > 0) { /* For a pNFS service, get the DS numbers. */ tsf = malloc(sizeof(*tsf), M_TEMP, M_WAITOK | M_ZERO); error = nfsrv_pnfsstatfs(tsf, vp->v_mount); if (error != 0) { free(tsf, M_TEMP); tsf = NULL; } } error = VFS_STATFS(vp->v_mount, sf); if (error == 0) { if (tsf != NULL) { sf->f_blocks = tsf->f_blocks; sf->f_bavail = tsf->f_bavail; sf->f_bfree = tsf->f_bfree; sf->f_bsize = tsf->f_bsize; } /* * Since NFS handles these values as unsigned on the * wire, there is no way to represent negative values, * so set them to 0. Without this, they will appear * to be very large positive values for clients like * Solaris10. */ if (sf->f_bavail < 0) sf->f_bavail = 0; if (sf->f_ffree < 0) sf->f_ffree = 0; } free(tsf, M_TEMP); NFSEXITCODE(error); return (error); } /* * Do the vnode op stuff for Open. Similar to nfsvno_createsub(), but * must handle nfsrv_opencheck() calls after any other access checks. */ void nfsvno_open(struct nfsrv_descript *nd, struct nameidata *ndp, nfsquad_t clientid, nfsv4stateid_t *stateidp, struct nfsstate *stp, int *exclusive_flagp, struct nfsvattr *nvap, int32_t *cverf, int create, NFSACL_T *aclp, nfsattrbit_t *attrbitp, struct ucred *cred, bool done_namei, struct nfsexstuff *exp, struct vnode **vpp) { struct vnode *vp = NULL; u_quad_t tempsize; struct nfsexstuff nes; struct thread *p = curthread; uint32_t oldrepstat; if (ndp->ni_vp == NULL) { /* * If nfsrv_opencheck() sets nd_repstat, done_namei needs to be * set true, since cleanup after nfsvno_namei() is needed. */ oldrepstat = nd->nd_repstat; nd->nd_repstat = nfsrv_opencheck(clientid, stateidp, stp, NULL, nd, p, nd->nd_repstat); if (nd->nd_repstat != 0 && oldrepstat == 0) done_namei = true; } if (!nd->nd_repstat) { if (ndp->ni_vp == NULL) { nd->nd_repstat = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr); /* For a pNFS server, create the data file on a DS. */ if (nd->nd_repstat == 0) { /* * Create a data file on a DS for a pNFS server. * This function just returns if not * running a pNFS DS or the creation fails. */ nfsrv_pnfscreate(ndp->ni_vp, &nvap->na_vattr, cred, p); } VOP_VPUT_PAIR(ndp->ni_dvp, nd->nd_repstat == 0 ? &ndp->ni_vp : NULL, false); nfsvno_relpathbuf(ndp); if (!nd->nd_repstat) { if (*exclusive_flagp) { *exclusive_flagp = 0; NFSVNO_ATTRINIT(nvap); nvap->na_atime.tv_sec = cverf[0]; nvap->na_atime.tv_nsec = cverf[1]; nd->nd_repstat = VOP_SETATTR(ndp->ni_vp, &nvap->na_vattr, cred); if (nd->nd_repstat != 0) { vput(ndp->ni_vp); ndp->ni_vp = NULL; nd->nd_repstat = NFSERR_NOTSUPP; } else NFSSETBIT_ATTRBIT(attrbitp, NFSATTRBIT_TIMEACCESS); } else { nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); } } vp = ndp->ni_vp; } else { nfsvno_relpathbuf(ndp); vp = ndp->ni_vp; if (create == NFSV4OPEN_CREATE) { if (ndp->ni_dvp == vp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); } if (NFSVNO_ISSETSIZE(nvap) && vp->v_type == VREG) { if (ndp->ni_cnd.cn_flags & RDONLY) NFSVNO_SETEXRDONLY(&nes); else NFSVNO_EXINIT(&nes); nd->nd_repstat = nfsvno_accchk(vp, VWRITE, cred, &nes, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, NULL); nd->nd_repstat = nfsrv_opencheck(clientid, stateidp, stp, vp, nd, p, nd->nd_repstat); if (!nd->nd_repstat) { tempsize = nvap->na_size; NFSVNO_ATTRINIT(nvap); nvap->na_size = tempsize; nd->nd_repstat = nfsvno_setattr(vp, nvap, cred, p, exp); } } else if (vp->v_type == VREG) { nd->nd_repstat = nfsrv_opencheck(clientid, stateidp, stp, vp, nd, p, nd->nd_repstat); } } } else if (done_namei) { KASSERT(create == NFSV4OPEN_CREATE, ("nfsvno_open: not create")); /* * done_namei is set when nfsvno_namei() has completed * successfully, but a subsequent error was set in * nd_repstat. As such, cleanup of the nfsvno_namei() * results is required. */ nfsvno_relpathbuf(ndp); if (ndp->ni_dvp == ndp->ni_vp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); if (ndp->ni_vp) vput(ndp->ni_vp); } *vpp = vp; NFSEXITCODE2(0, nd); } /* * Updates the file rev and sets the mtime and ctime * to the current clock time, returning the va_filerev and va_Xtime * values. * Return ESTALE to indicate the vnode is VIRF_DOOMED. */ int nfsvno_updfilerev(struct vnode *vp, struct nfsvattr *nvap, struct nfsrv_descript *nd, struct thread *p) { struct vattr va; VATTR_NULL(&va); vfs_timestamp(&va.va_mtime); if (NFSVOPISLOCKED(vp) != LK_EXCLUSIVE) { NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(vp)) return (ESTALE); } (void) VOP_SETATTR(vp, &va, nd->nd_cred); (void) nfsvno_getattr(vp, nvap, nd, p, 1, NULL); return (0); } /* * Glue routine to nfsv4_fillattr(). */ int 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, uint32_t clone_blksize) { struct statfs *sf; int error; sf = NULL; if (nfsrv_devidcnt > 0 && (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SPACEAVAIL) || NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SPACEFREE) || NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SPACETOTAL))) { sf = malloc(sizeof(*sf), M_TEMP, M_WAITOK | M_ZERO); error = nfsrv_pnfsstatfs(sf, mp); if (error != 0) { free(sf, M_TEMP); 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, clone_blksize); free(sf, M_TEMP); NFSEXITCODE2(0, nd); return (error); } /* * Convert a dirent d_type to a vnode type. */ static void nfs_dtypetovtype(struct nfsvattr *nvap, struct vnode *vp, uint8_t dtype) { if ((vn_irflag_read(vp) & VIRF_NAMEDDIR) != 0) { nvap->na_type = VREG; nvap->na_bsdflags |= SFBSD_NAMEDATTR; } else if (dtype <= DT_WHT) { nvap->na_type = dtype_to_vnode[dtype]; } else { nvap->na_type = VNON; } } /* Since the Readdir vnode ops vary, put the entire functions in here. */ /* * nfs readdir service * - mallocs what it thinks is enough to read * count rounded up to a multiple of DIRBLKSIZ <= NFS_MAXREADDIR * - calls VOP_READDIR() * - loops around building the reply * if the output generated exceeds count break out of loop * The NFSM_CLGET macro is used here so that the reply will be packed * tightly in mbuf clusters. * - it trims out records with d_fileno == 0 * this doesn't matter for Unix clients, but they might confuse clients * for other os'. * - it trims out records with d_type == DT_WHT * these cannot be seen through NFS (unless we extend the protocol) * The alternate call nfsrvd_readdirplus() does lookups as well. * PS: The NFS protocol spec. does not clarify what the "count" byte * argument is a count of.. just name strings and file id's or the * entire reply rpc or ... * I tried just file name and id sizes and it confused the Sun client, * so I am using the full rpc size now. The "paranoia.." comment refers * to including the status longwords that are not a part of the dir. * "entry" structures, but are in the rpc. */ int nfsrvd_readdir(struct nfsrv_descript *nd, int isdgram, struct vnode *vp, struct nfsexstuff *exp) { struct dirent *dp; u_int32_t *tl; int dirlen; char *cpos, *cend, *rbuf; struct nfsvattr at; int nlen, error = 0, getret = 1; int siz, cnt, fullsiz, eofflag, ncookies; u_int64_t off, toff, verf __unused; uint64_t *cookies = NULL, *cookiep; struct uio io; struct iovec iv; int is_ufs; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_postopattr(nd, getret, &at); goto out; } if (nd->nd_flag & ND_NFSV2) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); off = fxdr_unsigned(u_quad_t, *tl++); } else { NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); off = fxdr_hyper(tl); tl += 2; verf = fxdr_hyper(tl); tl += 2; } toff = off; cnt = fxdr_unsigned(int, *tl); if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0) cnt = NFS_SRVMAXDATA(nd); siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); fullsiz = siz; if (nd->nd_flag & ND_NFSV3) { nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); #if 0 /* * va_filerev is not sufficient as a cookie verifier, * since it is not supposed to change when entries are * removed/added unless that offset cookies returned to * the client are no longer valid. */ if (!nd->nd_repstat && toff && verf != at.na_filerev) nd->nd_repstat = NFSERR_BAD_COOKIE; #endif } if (!nd->nd_repstat && vp->v_type != VDIR) nd->nd_repstat = NFSERR_NOTDIR; if (nd->nd_repstat == 0 && cnt == 0) { if (nd->nd_flag & ND_NFSV2) /* NFSv2 does not have NFSERR_TOOSMALL */ nd->nd_repstat = EPERM; else nd->nd_repstat = NFSERR_TOOSMALL; } if (!nd->nd_repstat) nd->nd_repstat = nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, NULL); if (nd->nd_repstat) { vput(vp); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &at); goto out; } is_ufs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "ufs") == 0; rbuf = malloc(siz, M_TEMP, M_WAITOK); again: eofflag = 0; if (cookies) { free(cookies, M_TEMP); cookies = NULL; } iv.iov_base = rbuf; iv.iov_len = siz; io.uio_iov = &iv; io.uio_iovcnt = 1; io.uio_offset = (off_t)off; io.uio_resid = siz; io.uio_segflg = UIO_SYSSPACE; io.uio_rw = UIO_READ; io.uio_td = NULL; nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies, &cookies); off = (u_int64_t)io.uio_offset; if (io.uio_resid) siz -= io.uio_resid; if (!cookies && !nd->nd_repstat) nd->nd_repstat = NFSERR_PERM; if (nd->nd_flag & ND_NFSV3) { getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); if (!nd->nd_repstat) nd->nd_repstat = getret; } /* * Handles the failed cases. nd->nd_repstat == 0 past here. */ if (nd->nd_repstat) { vput(vp); free(rbuf, M_TEMP); if (cookies) free(cookies, M_TEMP); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &at); goto out; } /* * If nothing read, return eof * rpc reply */ if (siz == 0) { vput(vp); if (nd->nd_flag & ND_NFSV2) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); } else { nfsrv_postopattr(nd, getret, &at); NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); txdr_hyper(at.na_filerev, tl); tl += 2; } *tl++ = newnfs_false; *tl = newnfs_true; free(rbuf, M_TEMP); free(cookies, M_TEMP); goto out; } /* * Check for degenerate cases of nothing useful read. * If so go try again */ cpos = rbuf; cend = rbuf + siz; dp = (struct dirent *)cpos; cookiep = cookies; /* * For some reason FreeBSD's ufs_readdir() chooses to back the * directory offset up to a block boundary, so it is necessary to * skip over the records that precede the requested offset. This * requires the assumption that file offset cookies monotonically * increase. */ while (cpos < cend && ncookies > 0 && (dp->d_fileno == 0 || dp->d_type == DT_WHT || (is_ufs == 1 && ((u_quad_t)(*cookiep)) <= toff))) { cpos += dp->d_reclen; dp = (struct dirent *)cpos; cookiep++; ncookies--; } if (cpos >= cend || ncookies == 0) { siz = fullsiz; toff = off; goto again; } vput(vp); /* * If cnt > MCLBYTES and the reply will not be saved, use * ext_pgs mbufs for TLS. * For NFSv4.0, we do not know for sure if the reply will * be saved, so do not use ext_pgs mbufs for NFSv4.0. */ if (cnt > MCLBYTES && siz > MCLBYTES && (nd->nd_flag & (ND_TLS | ND_EXTPG | ND_SAVEREPLY)) == ND_TLS && (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4) nd->nd_flag |= ND_EXTPG; /* * dirlen is the size of the reply, including all XDR and must * not exceed cnt. For NFSv2, RFC1094 didn't clearly indicate * if the XDR should be included in "count", but to be safe, we do. * (Include the two booleans at the end of the reply in dirlen now.) */ if (nd->nd_flag & ND_NFSV3) { nfsrv_postopattr(nd, getret, &at); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); txdr_hyper(at.na_filerev, tl); dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED; } else { dirlen = 2 * NFSX_UNSIGNED; } /* Loop through the records and build reply */ while (cpos < cend && ncookies > 0) { nlen = dp->d_namlen; if (dp->d_fileno != 0 && dp->d_type != DT_WHT && nlen <= NFS_MAXNAMLEN) { if (nd->nd_flag & ND_NFSV3) dirlen += (6*NFSX_UNSIGNED + NFSM_RNDUP(nlen)); else dirlen += (4*NFSX_UNSIGNED + NFSM_RNDUP(nlen)); if (dirlen > cnt) { eofflag = 0; break; } /* * Build the directory record xdr from * the dirent entry. */ if (nd->nd_flag & ND_NFSV3) { NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); *tl++ = newnfs_true; txdr_hyper(dp->d_fileno, tl); } else { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = newnfs_true; *tl = txdr_unsigned(dp->d_fileno); } (void) nfsm_strtom(nd, dp->d_name, nlen); if (nd->nd_flag & ND_NFSV3) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); txdr_hyper(*cookiep, tl); } else { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(*cookiep); } } cpos += dp->d_reclen; dp = (struct dirent *)cpos; cookiep++; ncookies--; } if (cpos < cend) eofflag = 0; NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = newnfs_false; if (eofflag) *tl = newnfs_true; else *tl = newnfs_false; free(rbuf, M_TEMP); free(cookies, M_TEMP); out: NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * Readdirplus for V3 and Readdir for V4. */ int nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, struct vnode *vp, struct nfsexstuff *exp) { struct dirent *dp; uint32_t clone_blksize, *tl; int dirlen; char *cpos, *cend, *rbuf; struct vnode *nvp; fhandle_t nfh; struct nfsvattr nva, at, *nvap = &nva; struct mbuf *mb0, *mb1; struct nfsreferral *refp; int nlen, r, error = 0, getret = 1, ret, usevget = 1; int siz, cnt, fullsiz, eofflag, ncookies, entrycnt; caddr_t bpos0, bpos1; u_int64_t off, toff, verf __unused; uint64_t *cookies = NULL, *cookiep; nfsattrbit_t attrbits, rderrbits, savbits, refbits; struct uio io; struct iovec iv; struct componentname cn; int at_root, is_ufs, is_zfs, needs_unbusy, supports_nfsv4acls; struct mount *mp, *new_mp; uint64_t mounted_on_fileno; struct thread *p = curthread; int bextpg0, bextpg1, bextpgsiz0, bextpgsiz1; size_t atsiz; long pathval; bool has_hiddensystem, has_namedattr, xattrsupp; if (nd->nd_repstat) { nfsrv_postopattr(nd, getret, &at); goto out; } NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); off = fxdr_hyper(tl); toff = off; tl += 2; verf = fxdr_hyper(tl); tl += 2; siz = fxdr_unsigned(int, *tl++); cnt = fxdr_unsigned(int, *tl); /* * Use the server's maximum data transfer size as the upper bound * on reply datalen. */ if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0) cnt = NFS_SRVMAXDATA(nd); /* * siz is a "hint" of how much directory information (name, fileid, * cookie) should be in the reply. At least one client "hints" 0, * so I set it to cnt for that case. I also round it up to the * next multiple of DIRBLKSIZ. * Since the size of a Readdirplus directory entry reply will always * be greater than a directory entry returned by VOP_READDIR(), it * does not make sense to read more than NFS_SRVMAXDATA() via * VOP_READDIR(). */ if (siz <= 0) siz = cnt; else if (siz > NFS_SRVMAXDATA(nd)) siz = NFS_SRVMAXDATA(nd); siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); if (nd->nd_flag & ND_NFSV4) { error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error) goto nfsmout; NFSSET_ATTRBIT(&savbits, &attrbits); NFSSET_ATTRBIT(&refbits, &attrbits); NFSCLRNOTFILLABLE_ATTRBIT(&attrbits, nd); NFSZERO_ATTRBIT(&rderrbits); NFSSETBIT_ATTRBIT(&rderrbits, NFSATTRBIT_RDATTRERROR); /* * If these 4 bits are the only attributes requested by the * client, they can be satisfied without acquiring the vnode * for the file object unless it is a directory. * This will be indicated by savbits being all 0s. */ NFSCLRBIT_ATTRBIT(&savbits, NFSATTRBIT_TYPE); NFSCLRBIT_ATTRBIT(&savbits, NFSATTRBIT_FILEID); NFSCLRBIT_ATTRBIT(&savbits, NFSATTRBIT_MOUNTEDONFILEID); NFSCLRBIT_ATTRBIT(&savbits, NFSATTRBIT_RDATTRERROR); } else { NFSZERO_ATTRBIT(&attrbits); } fullsiz = siz; nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); #if 0 if (!nd->nd_repstat) { if (off && verf != at.na_filerev) { /* * va_filerev is not sufficient as a cookie verifier, * since it is not supposed to change when entries are * removed/added unless that offset cookies returned to * the client are no longer valid. */ if (nd->nd_flag & ND_NFSV4) { nd->nd_repstat = NFSERR_NOTSAME; } else { nd->nd_repstat = NFSERR_BAD_COOKIE; } } } #endif if (!nd->nd_repstat && vp->v_type != VDIR) nd->nd_repstat = NFSERR_NOTDIR; if (!nd->nd_repstat && cnt == 0) nd->nd_repstat = NFSERR_TOOSMALL; if (!nd->nd_repstat) nd->nd_repstat = nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, NULL); if (nd->nd_repstat) { vput(vp); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &at); goto out; } is_ufs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "ufs") == 0; is_zfs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "zfs") == 0; rbuf = malloc(siz, M_TEMP, M_WAITOK); again: eofflag = 0; if (cookies) { free(cookies, M_TEMP); cookies = NULL; } iv.iov_base = rbuf; iv.iov_len = siz; io.uio_iov = &iv; io.uio_iovcnt = 1; io.uio_offset = (off_t)off; io.uio_resid = siz; io.uio_segflg = UIO_SYSSPACE; io.uio_rw = UIO_READ; io.uio_td = NULL; nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies, &cookies); off = (u_int64_t)io.uio_offset; if (io.uio_resid) siz -= io.uio_resid; getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); if (!cookies && !nd->nd_repstat) nd->nd_repstat = NFSERR_PERM; if (!nd->nd_repstat) nd->nd_repstat = getret; if (nd->nd_repstat) { vput(vp); if (cookies) free(cookies, M_TEMP); free(rbuf, M_TEMP); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &at); goto out; } /* * If nothing read, return eof * rpc reply */ if (siz == 0) { ateof: vput(vp); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &at); NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); txdr_hyper(at.na_filerev, tl); tl += 2; *tl++ = newnfs_false; *tl = newnfs_true; free(cookies, M_TEMP); free(rbuf, M_TEMP); goto out; } /* * Check for degenerate cases of nothing useful read. * If so go try again */ cpos = rbuf; cend = rbuf + siz; dp = (struct dirent *)cpos; cookiep = cookies; /* * For some reason FreeBSD's ufs_readdir() chooses to back the * directory offset up to a block boundary, so it is necessary to * skip over the records that precede the requested offset. This * requires the assumption that file offset cookies monotonically * increase. */ while (cpos < cend && ncookies > 0 && (dp->d_fileno == 0 || dp->d_type == DT_WHT || (is_ufs == 1 && ((u_quad_t)(*cookiep)) <= toff) || ((nd->nd_flag & ND_NFSV4) && ((dp->d_namlen == 1 && dp->d_name[0] == '.') || (dp->d_namlen==2 && dp->d_name[0]=='.' && dp->d_name[1]=='.'))))) { cpos += dp->d_reclen; dp = (struct dirent *)cpos; cookiep++; ncookies--; } if (cpos >= cend || ncookies == 0) { if (eofflag != 0) goto ateof; siz = fullsiz; toff = off; goto again; } /* * Busy the file system so that the mount point won't go away * and, as such, VFS_VGET() can be used safely. */ mp = vp->v_mount; vfs_ref(mp); NFSVOPUNLOCK(vp); nd->nd_repstat = vfs_busy(mp, 0); vfs_rel(mp); if (nd->nd_repstat != 0) { vrele(vp); free(cookies, M_TEMP); free(rbuf, M_TEMP); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &at); goto out; } /* * Check to see if entries in this directory can be safely acquired * via VFS_VGET() or if a switch to VOP_LOOKUP() is required. * ZFS snapshot directories need VOP_LOOKUP(), so that any * automount of the snapshot directory that is required will * be done. * This needs to be done here for NFSv4, since NFSv4 never does * a VFS_VGET() for "." or "..". */ if (is_zfs == 1) { r = VFS_VGET(mp, at.na_fileid, LK_SHARED, &nvp); if (r == EOPNOTSUPP) { usevget = 0; cn.cn_nameiop = LOOKUP; cn.cn_lkflags = LK_SHARED | LK_RETRY; cn.cn_cred = nd->nd_cred; } else if (r == 0) vput(nvp); } /* * If the reply is likely to exceed MCLBYTES and the reply will * not be saved, use ext_pgs mbufs for TLS. * It is difficult to predict how large each entry will be and * how many entries have been read, so just assume the directory * entries grow by a factor of 4 when attributes are included. * For NFSv4.0, we do not know for sure if the reply will * be saved, so do not use ext_pgs mbufs for NFSv4.0. */ if (cnt > MCLBYTES && siz > MCLBYTES / 4 && (nd->nd_flag & (ND_TLS | ND_EXTPG | ND_SAVEREPLY)) == ND_TLS && (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4) nd->nd_flag |= ND_EXTPG; /* * Save this position, in case there is an error before one entry * is created. */ mb0 = nd->nd_mb; bpos0 = nd->nd_bpos; bextpg0 = nd->nd_bextpg; bextpgsiz0 = nd->nd_bextpgsiz; /* * Fill in the first part of the reply. * dirlen is the reply length in bytes and cannot exceed cnt. * (Include the two booleans at the end of the reply in dirlen now, * so we recognize when we have exceeded cnt.) */ if (nd->nd_flag & ND_NFSV3) { dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED; nfsrv_postopattr(nd, getret, &at); } else { dirlen = NFSX_VERF + 2 * NFSX_UNSIGNED; } NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); txdr_hyper(at.na_filerev, tl); /* * Save this position, in case there is an empty reply needed. */ mb1 = nd->nd_mb; bpos1 = nd->nd_bpos; bextpg1 = nd->nd_bextpg; bextpgsiz1 = nd->nd_bextpgsiz; /* Loop through the records and build reply */ entrycnt = 0; while (cpos < cend && ncookies > 0 && dirlen < cnt) { nlen = dp->d_namlen; if (dp->d_fileno != 0 && dp->d_type != DT_WHT && nlen <= NFS_MAXNAMLEN && ((nd->nd_flag & ND_NFSV3) || nlen > 2 || (nlen==2 && (dp->d_name[0]!='.' || dp->d_name[1]!='.')) || (nlen == 1 && dp->d_name[0] != '.'))) { /* * Save the current position in the reply, in case * this entry exceeds cnt. */ mb1 = nd->nd_mb; bpos1 = nd->nd_bpos; bextpg1 = nd->nd_bextpg; bextpgsiz1 = nd->nd_bextpgsiz; /* * For readdir_and_lookup get the vnode using * the file number. */ nvp = NULL; refp = NULL; r = 0; at_root = 0; needs_unbusy = 0; new_mp = mp; mounted_on_fileno = (uint64_t)dp->d_fileno; if ((nd->nd_flag & ND_NFSV3) || NFSNONZERO_ATTRBIT(&savbits) || dp->d_type == DT_UNKNOWN || (dp->d_type == DT_DIR && nfsrv_enable_crossmntpt != 0)) { if (nd->nd_flag & ND_NFSV4) refp = nfsv4root_getreferral(NULL, vp, dp->d_fileno); if (refp == NULL) { if (usevget) r = VFS_VGET(mp, dp->d_fileno, LK_SHARED, &nvp); else r = EOPNOTSUPP; if (r == 0 && (vn_irflag_read(vp) & VIRF_NAMEDDIR) != 0) vn_irflag_set_cond(nvp, VIRF_NAMEDATTR); if (r == EOPNOTSUPP) { if (usevget) { usevget = 0; cn.cn_nameiop = LOOKUP; cn.cn_lkflags = LK_SHARED | LK_RETRY; cn.cn_cred = nd->nd_cred; } cn.cn_nameptr = dp->d_name; cn.cn_namelen = nlen; cn.cn_flags = ISLASTCN | NOFOLLOW | LOCKLEAF; if ((vn_irflag_read(vp) & VIRF_NAMEDDIR) != 0) cn.cn_flags |= OPENNAMED; if (nlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') cn.cn_flags |= ISDOTDOT; if (NFSVOPLOCK(vp, LK_SHARED) != 0) { nd->nd_repstat = EPERM; break; } if ((vp->v_vflag & VV_ROOT) != 0 && (cn.cn_flags & ISDOTDOT) != 0) { vref(vp); nvp = vp; r = 0; } else { r = VOP_LOOKUP(vp, &nvp, &cn); if (vp != nvp) NFSVOPUNLOCK(vp); } } /* * For NFSv4, check to see if nvp is * a mount point and get the mount * point vnode, as required. */ if (r == 0 && nfsrv_enable_crossmntpt != 0 && (nd->nd_flag & ND_NFSV4) != 0 && nvp->v_type == VDIR && nvp->v_mountedhere != NULL) { new_mp = nvp->v_mountedhere; r = vfs_busy(new_mp, 0); vput(nvp); nvp = NULL; if (r == 0) { r = VFS_ROOT(new_mp, LK_SHARED, &nvp); needs_unbusy = 1; if (r == 0) at_root = 1; } } } /* * If we failed to look up the entry, then it * has become invalid, most likely removed. */ if (r != 0) { if (needs_unbusy) vfs_unbusy(new_mp); goto invalid; } KASSERT(refp != NULL || nvp != NULL, ("%s: undetected lookup error", __func__)); if (refp == NULL && ((nd->nd_flag & ND_NFSV3) || NFSNONZERO_ATTRBIT(&attrbits))) { r = nfsvno_getfh(nvp, &nfh, p); if (!r) r = nfsvno_getattr(nvp, nvap, nd, p, 1, &attrbits); if (r == 0 && is_zfs == 1 && nfsrv_enable_crossmntpt != 0 && (nd->nd_flag & ND_NFSV4) != 0 && nvp->v_type == VDIR && vp->v_mount != nvp->v_mount) { /* * For a ZFS snapshot, there is a * pseudo mount that does not set * v_mountedhere, so it needs to * be detected via a different * mount structure. */ at_root = 1; if (new_mp == mp) new_mp = nvp->v_mount; } } /* * If we failed to get attributes of the entry, * then just skip it for NFSv3 (the traditional * behavior in the old NFS server). * For NFSv4 the behavior is controlled by * RDATTRERROR: we either ignore the error or * fail the request. * The exception is EOPNOTSUPP, which can be * returned by nfsvno_getfh() for certain * file systems, such as devfs. This indicates * that the file system cannot be exported, * so just skip over the entry. * Note that RDATTRERROR is never set for NFSv3. */ if (r != 0) { if (!NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR) || r == EOPNOTSUPP) { vput(nvp); if (needs_unbusy != 0) vfs_unbusy(new_mp); if ((nd->nd_flag & ND_NFSV3) || r == EOPNOTSUPP) goto invalid; nd->nd_repstat = r; break; } } } else if (NFSNONZERO_ATTRBIT(&attrbits)) { /* Only need Type and/or Fileid. */ VATTR_NULL(&nvap->na_vattr); nvap->na_fileid = dp->d_fileno; nfs_dtypetovtype(nvap, vp, dp->d_type); } /* * Build the directory record xdr */ if (nd->nd_flag & ND_NFSV3) { NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); *tl++ = newnfs_true; txdr_hyper(dp->d_fileno, tl); dirlen += nfsm_strtom(nd, dp->d_name, nlen); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); txdr_hyper(*cookiep, tl); nfsrv_postopattr(nd, 0, nvap); dirlen += nfsm_fhtom(NULL, nd, (u_int8_t *)&nfh, 0, 1); dirlen += (5*NFSX_UNSIGNED+NFSX_V3POSTOPATTR); if (nvp != NULL) vput(nvp); } else { NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); *tl++ = newnfs_true; txdr_hyper(*cookiep, tl); dirlen += nfsm_strtom(nd, dp->d_name, nlen); xattrsupp = false; has_hiddensystem = false; has_namedattr = false; clone_blksize = 0; if (nvp != NULL) { supports_nfsv4acls = nfs_supportsnfsv4acls(nvp); if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_XATTRSUPPORT)) { ret = VOP_GETEXTATTR(nvp, EXTATTR_NAMESPACE_USER, "xxx", NULL, &atsiz, nd->nd_cred, p); xattrsupp = ret != EOPNOTSUPP; } if (VOP_PATHCONF(nvp, _PC_HAS_HIDDENSYSTEM, &pathval) != 0) pathval = 0; has_hiddensystem = pathval > 0; pathval = 0; if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_NAMEDATTR) && VOP_PATHCONF(nvp, _PC_HAS_NAMEDATTR, &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; if (refp != NULL) { dirlen += nfsrv_putreferralattr(nd, &refbits, refp, 0, &nd->nd_repstat); if (nd->nd_repstat) { if (nvp != NULL) vrele(nvp); if (needs_unbusy != 0) vfs_unbusy(new_mp); break; } } else if (r) { dirlen += nfsvno_fillattr(nd, new_mp, nvp, nvap, &nfh, r, &rderrbits, nd->nd_cred, p, isdgram, 0, supports_nfsv4acls, at_root, mounted_on_fileno, xattrsupp, 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, clone_blksize); } if (nvp != NULL) vrele(nvp); dirlen += (3 * NFSX_UNSIGNED); } if (needs_unbusy != 0) vfs_unbusy(new_mp); if (dirlen <= cnt) entrycnt++; } invalid: cpos += dp->d_reclen; dp = (struct dirent *)cpos; cookiep++; ncookies--; } vrele(vp); vfs_unbusy(mp); /* * If dirlen > cnt, we must strip off the last entry. If that * results in an empty reply, report NFSERR_TOOSMALL. */ if (dirlen > cnt || nd->nd_repstat) { if (!nd->nd_repstat && entrycnt == 0) nd->nd_repstat = NFSERR_TOOSMALL; if (nd->nd_repstat) { nfsm_trimtrailing(nd, mb0, bpos0, bextpg0, bextpgsiz0); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &at); } else nfsm_trimtrailing(nd, mb1, bpos1, bextpg1, bextpgsiz1); eofflag = 0; } else if (cpos < cend) eofflag = 0; if (!nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = newnfs_false; if (eofflag) *tl = newnfs_true; else *tl = newnfs_false; } free(cookies, M_TEMP); free(rbuf, M_TEMP); out: NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * Get the settable attributes out of the mbuf list. * (Return 0 or EBADRPC) */ int nfsrv_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p) { u_int32_t *tl; struct nfsv2_sattr *sp; int error = 0, toclient = 0; switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { case ND_NFSV2: NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); /* * Some old clients didn't fill in the high order 16bits. * --> check the low order 2 bytes for 0xffff */ if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) nvap->na_mode = nfstov_mode(sp->sa_mode); if (sp->sa_uid != newnfs_xdrneg1) nvap->na_uid = fxdr_unsigned(uid_t, sp->sa_uid); if (sp->sa_gid != newnfs_xdrneg1) nvap->na_gid = fxdr_unsigned(gid_t, sp->sa_gid); if (sp->sa_size != newnfs_xdrneg1) nvap->na_size = fxdr_unsigned(u_quad_t, sp->sa_size); if (sp->sa_atime.nfsv2_sec != newnfs_xdrneg1) { #ifdef notyet fxdr_nfsv2time(&sp->sa_atime, &nvap->na_atime); #else nvap->na_atime.tv_sec = fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec); nvap->na_atime.tv_nsec = 0; #endif } if (sp->sa_mtime.nfsv2_sec != newnfs_xdrneg1) fxdr_nfsv2time(&sp->sa_mtime, &nvap->na_mtime); break; case ND_NFSV3: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); if (*tl == newnfs_true) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); nvap->na_mode = nfstov_mode(*tl); } NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); if (*tl == newnfs_true) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); nvap->na_uid = fxdr_unsigned(uid_t, *tl); } NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); if (*tl == newnfs_true) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); nvap->na_gid = fxdr_unsigned(gid_t, *tl); } NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); if (*tl == newnfs_true) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); nvap->na_size = fxdr_hyper(tl); } NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); switch (fxdr_unsigned(int, *tl)) { case NFSV3SATTRTIME_TOCLIENT: NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); fxdr_nfsv3time(tl, &nvap->na_atime); toclient = 1; break; case NFSV3SATTRTIME_TOSERVER: vfs_timestamp(&nvap->na_atime); nvap->na_vaflags |= VA_UTIMES_NULL; break; } NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); switch (fxdr_unsigned(int, *tl)) { case NFSV3SATTRTIME_TOCLIENT: NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); fxdr_nfsv3time(tl, &nvap->na_mtime); nvap->na_vaflags &= ~VA_UTIMES_NULL; break; case NFSV3SATTRTIME_TOSERVER: vfs_timestamp(&nvap->na_mtime); if (!toclient) nvap->na_vaflags |= VA_UTIMES_NULL; break; } break; case ND_NFSV4: error = nfsv4_sattr(nd, vp, nvap, attrbitp, aclp, p); } nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * Handle the setable attributes for V4. * Returns NFSERR_BADXDR if it can't be parsed, 0 otherwise. */ int nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p) { u_int32_t *tl; int attrsum = 0; int i, j; int error, attrsize, bitpos, aclsize, aceerr, retnotsup = 0; int moderet, toclient = 0; u_char *cp, namestr[NFSV4_SMALLSTR + 1]; uid_t uid; gid_t gid; u_short mode, mask; /* Same type as va_mode. */ struct vattr va; error = nfsrv_getattrbits(nd, attrbitp, NULL, &retnotsup); if (error) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); attrsize = fxdr_unsigned(int, *tl); /* * Loop around getting the setable attributes. If an unsupported * one is found, set nd_repstat == NFSERR_ATTRNOTSUPP and return. * Once nd_repstat != 0, do not set the attribute value, but keep * parsing the attribute(s). */ if (retnotsup) { nd->nd_repstat = NFSERR_ATTRNOTSUPP; bitpos = NFSATTRBIT_MAX; } else { bitpos = 0; if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_HIDDEN) || NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SYSTEM)) nvap->na_flags = 0; } moderet = 0; for (; bitpos < NFSATTRBIT_MAX; bitpos++) { if (attrsum > attrsize) { error = NFSERR_BADXDR; goto nfsmout; } if (NFSISSET_ATTRBIT(attrbitp, bitpos)) switch (bitpos) { case NFSATTRBIT_SIZE: NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); if (!nd->nd_repstat) { if (vp != NULL && vp->v_type != VREG) nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL; else nvap->na_size = fxdr_hyper(tl); } attrsum += NFSX_HYPER; break; case NFSATTRBIT_ACL: error = nfsrv_dissectacl(nd, aclp, true, &aceerr, &aclsize, p); if (error) goto nfsmout; if (aceerr && !nd->nd_repstat) nd->nd_repstat = aceerr; attrsum += aclsize; break; case NFSATTRBIT_ARCHIVE: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); if (!nd->nd_repstat) nd->nd_repstat = NFSERR_ATTRNOTSUPP; attrsum += NFSX_UNSIGNED; break; case NFSATTRBIT_HIDDEN: NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); if (nd->nd_repstat == 0) { if (*tl == newnfs_true) nvap->na_flags |= UF_HIDDEN; } attrsum += NFSX_UNSIGNED; break; case NFSATTRBIT_MIMETYPE: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); i = fxdr_unsigned(int, *tl); error = nfsm_advance(nd, NFSM_RNDUP(i), -1); if (error) goto nfsmout; if (!nd->nd_repstat) nd->nd_repstat = NFSERR_ATTRNOTSUPP; attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); break; case NFSATTRBIT_MODE: moderet = NFSERR_INVAL; /* Can't do MODESETMASKED. */ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); if (!nd->nd_repstat) nvap->na_mode = nfstov_mode(*tl); attrsum += NFSX_UNSIGNED; break; case NFSATTRBIT_OWNER: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); j = fxdr_unsigned(int, *tl); if (j < 0) { error = NFSERR_BADXDR; goto nfsmout; } if (j > NFSV4_SMALLSTR) cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); else cp = namestr; error = nfsrv_mtostr(nd, cp, j); if (error) { if (j > NFSV4_SMALLSTR) free(cp, M_NFSSTRING); goto nfsmout; } if (!nd->nd_repstat) { nd->nd_repstat = nfsv4_strtouid(nd, cp, j, &uid); if (!nd->nd_repstat) nvap->na_uid = uid; } if (j > NFSV4_SMALLSTR) free(cp, M_NFSSTRING); attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); break; case NFSATTRBIT_OWNERGROUP: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); j = fxdr_unsigned(int, *tl); if (j < 0) { error = NFSERR_BADXDR; goto nfsmout; } if (j > NFSV4_SMALLSTR) cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); else cp = namestr; error = nfsrv_mtostr(nd, cp, j); if (error) { if (j > NFSV4_SMALLSTR) free(cp, M_NFSSTRING); goto nfsmout; } if (!nd->nd_repstat) { nd->nd_repstat = nfsv4_strtogid(nd, cp, j, &gid); if (!nd->nd_repstat) nvap->na_gid = gid; } if (j > NFSV4_SMALLSTR) free(cp, M_NFSSTRING); attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); break; case NFSATTRBIT_SYSTEM: NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); if (nd->nd_repstat == 0) { if (*tl == newnfs_true) nvap->na_flags |= UF_SYSTEM; } attrsum += NFSX_UNSIGNED; break; case NFSATTRBIT_TIMEACCESSSET: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); attrsum += NFSX_UNSIGNED; if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) { NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); if (!nd->nd_repstat) fxdr_nfsv4time(tl, &nvap->na_atime); toclient = 1; attrsum += NFSX_V4TIME; } else if (!nd->nd_repstat) { vfs_timestamp(&nvap->na_atime); nvap->na_vaflags |= VA_UTIMES_NULL; } break; case NFSATTRBIT_TIMEBACKUP: NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); if (!nd->nd_repstat) nd->nd_repstat = NFSERR_ATTRNOTSUPP; attrsum += NFSX_V4TIME; break; case NFSATTRBIT_TIMECREATE: NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); if (!nd->nd_repstat) fxdr_nfsv4time(tl, &nvap->na_btime); attrsum += NFSX_V4TIME; break; case NFSATTRBIT_TIMEMODIFYSET: NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); attrsum += NFSX_UNSIGNED; if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) { NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); if (!nd->nd_repstat) fxdr_nfsv4time(tl, &nvap->na_mtime); nvap->na_vaflags &= ~VA_UTIMES_NULL; attrsum += NFSX_V4TIME; } else if (!nd->nd_repstat) { vfs_timestamp(&nvap->na_mtime); if (!toclient) nvap->na_vaflags |= VA_UTIMES_NULL; } break; case NFSATTRBIT_MODESETMASKED: NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); mode = fxdr_unsigned(u_short, *tl++); mask = fxdr_unsigned(u_short, *tl); /* * vp == NULL implies an Open/Create operation. * This attribute can only be used for Setattr and * only for NFSv4.1 or higher. * If moderet != 0, a mode attribute has also been * specified and this attribute cannot be done in the * same Setattr operation. */ if (!nd->nd_repstat) { if ((nd->nd_flag & ND_NFSV41) == 0) nd->nd_repstat = NFSERR_ATTRNOTSUPP; else if ((mode & ~07777) != 0 || (mask & ~07777) != 0 || vp == NULL) nd->nd_repstat = NFSERR_INVAL; else if (moderet == 0) moderet = VOP_GETATTR(vp, &va, nd->nd_cred); if (moderet == 0) nvap->na_mode = (mode & mask) | (va.va_mode & ~mask); else nd->nd_repstat = moderet; } attrsum += 2 * NFSX_UNSIGNED; break; case NFSATTRBIT_MODEUMASK: NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); mode = fxdr_unsigned(u_short, *tl++); mask = fxdr_unsigned(u_short, *tl); /* * If moderet != 0, mode has already been done. * If vp != NULL, this is not a file object creation. */ if (!nd->nd_repstat) { if ((nd->nd_flag & ND_NFSV42) == 0) nd->nd_repstat = NFSERR_ATTRNOTSUPP; else if ((mask & ~0777) != 0 || vp != NULL || moderet != 0) nd->nd_repstat = NFSERR_INVAL; else nvap->na_mode = (mode & ~mask); } attrsum += 2 * NFSX_UNSIGNED; break; default: nd->nd_repstat = NFSERR_ATTRNOTSUPP; /* * set bitpos so we drop out of the loop. */ bitpos = NFSATTRBIT_MAX; break; } } /* * some clients pad the attrlist, so we need to skip over the * padding. This also skips over unparsed non-supported attributes. */ if (attrsum > attrsize) { error = NFSERR_BADXDR; } else { attrsize = NFSM_RNDUP(attrsize); if (attrsum < attrsize) error = nfsm_advance(nd, attrsize - attrsum, -1); } nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * Check/setup export credentials. */ int nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp, struct ucred *credanon, bool testsec) { int error; /* * Check/setup credentials. */ if (nd->nd_flag & ND_GSS) exp->nes_exflag &= ~MNT_EXPORTANON; /* * Check to see if the operation is allowed for this security flavor. */ error = 0; if (testsec) { error = nfsvno_testexp(nd, exp); if (error != 0) goto out; } /* * Check to see if the file system is exported V4 only. */ if (NFSVNO_EXV4ONLY(exp) && !(nd->nd_flag & ND_NFSV4)) { error = NFSERR_PROGNOTV4; goto out; } /* * Now, map the user credentials. * (Note that ND_AUTHNONE will only be set for an NFSv3 * Fsinfo RPC. If set for anything else, this code might need * to change.) */ if (NFSVNO_EXPORTED(exp)) { if (((nd->nd_flag & ND_GSS) == 0 && nd->nd_cred->cr_uid == 0) || NFSVNO_EXPORTANON(exp) || (nd->nd_flag & ND_AUTHNONE) != 0) { nd->nd_cred->cr_uid = credanon->cr_uid; nd->nd_cred->cr_gid = credanon->cr_gid; crsetgroups(nd->nd_cred, credanon->cr_ngroups, credanon->cr_groups); } else if ((nd->nd_flag & ND_GSS) == 0) { /* * If using AUTH_SYS, call nfsrv_getgrpscred() to see * if there is a replacement credential with a group * list set up by "nfsuserd -manage-gids". * If there is no replacement, nfsrv_getgrpscred() * simply returns its argument. */ nd->nd_cred = nfsrv_getgrpscred(nd->nd_cred); } } out: NFSEXITCODE2(error, nd); return (error); } /* * Check exports. */ int nfsvno_checkexp(struct mount *mp, struct sockaddr *nam, struct nfsexstuff *exp, struct ucred **credp) { int error; error = 0; *credp = NULL; MNT_ILOCK(mp); if (mp->mnt_exjail == NULL || mp->mnt_exjail->cr_prison != curthread->td_ucred->cr_prison) error = EACCES; MNT_IUNLOCK(mp); if (error == 0) error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, &exp->nes_numsecflavor, exp->nes_secflavors); if (error) { if (NFSD_VNET(nfs_rootfhset)) { exp->nes_exflag = 0; exp->nes_numsecflavor = 0; error = 0; } } else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor > MAXSECFLAVORS) { printf("nfsvno_checkexp: numsecflavors out of range\n"); exp->nes_numsecflavor = 0; error = EACCES; } NFSEXITCODE(error); return (error); } /* * Get a vnode for a file handle and export stuff. */ int nfsvno_fhtovp(struct mount *mp, fhandle_t *fhp, struct sockaddr *nam, int lktype, struct vnode **vpp, struct nfsexstuff *exp, struct ucred **credp) { int error; *credp = NULL; exp->nes_numsecflavor = 0; error = VFS_FHTOVP(mp, &fhp->fh_fid, lktype, vpp); if (error != 0) /* Make sure the server replies ESTALE to the client. */ error = ESTALE; if (nam && !error) { MNT_ILOCK(mp); if (mp->mnt_exjail == NULL || mp->mnt_exjail->cr_prison != curthread->td_ucred->cr_prison) error = EACCES; MNT_IUNLOCK(mp); if (error == 0) error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, &exp->nes_numsecflavor, exp->nes_secflavors); if (error) { if (NFSD_VNET(nfs_rootfhset)) { exp->nes_exflag = 0; exp->nes_numsecflavor = 0; error = 0; } else { vput(*vpp); } } else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor > MAXSECFLAVORS) { printf("nfsvno_fhtovp: numsecflavors out of range\n"); exp->nes_numsecflavor = 0; error = EACCES; vput(*vpp); } } NFSEXITCODE(error); return (error); } /* * nfsd_fhtovp() - convert a fh to a vnode ptr * - look up fsid in mount list (if not found ret error) * - get vp and export rights by calling nfsvno_fhtovp() * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon * for AUTH_SYS * - if mpp != NULL, return the mount point so that it can * be used for vn_finished_write() by the caller */ void nfsd_fhtovp(struct nfsrv_descript *nd, struct nfsrvfh *nfp, int lktype, struct vnode **vpp, struct nfsexstuff *exp, struct mount **mpp, int startwrite, int nextop) { struct mount *mp, *mpw; struct ucred *credanon; fhandle_t *fhp; int error; if (mpp != NULL) *mpp = NULL; *vpp = NULL; fhp = (fhandle_t *)nfp->nfsrvfh_data; mp = vfs_busyfs(&fhp->fh_fsid); if (mp == NULL) { nd->nd_repstat = ESTALE; goto out; } if (startwrite) { mpw = mp; error = vn_start_write(NULL, &mpw, V_WAIT); if (error != 0) { mpw = NULL; vfs_unbusy(mp); nd->nd_repstat = ESTALE; goto out; } if (lktype == LK_SHARED && !(MNT_SHARED_WRITES(mp))) lktype = LK_EXCLUSIVE; } else mpw = NULL; nd->nd_repstat = nfsvno_fhtovp(mp, fhp, nd->nd_nam, lktype, vpp, exp, &credanon); vfs_unbusy(mp); if (nd->nd_repstat == 0 && nfp->nfsrvfh_len >= NFSX_MYFH + NFSX_V4NAMEDDIRFH && nfp->nfsrvfh_len <= NFSX_MYFH + NFSX_V4NAMEDATTRFH) { if (nfp->nfsrvfh_len == NFSX_MYFH + NFSX_V4NAMEDDIRFH) vn_irflag_set_cond(*vpp, VIRF_NAMEDDIR); else vn_irflag_set_cond(*vpp, VIRF_NAMEDATTR); } /* * For NFSv4 without a pseudo root fs, unexported file handles * can be returned, so that Lookup works everywhere. */ if (!nd->nd_repstat && exp->nes_exflag == 0 && !(nd->nd_flag & ND_NFSV4)) { vput(*vpp); *vpp = NULL; nd->nd_repstat = EACCES; } /* * Personally, I've never seen any point in requiring a * reserved port#, since only in the rare case where the * clients are all boxes with secure system privileges, * does it provide any enhanced security, but... some people * believe it to be useful and keep putting this code back in. * (There is also some "security checker" out there that * complains if the nfs server doesn't enforce this.) * However, note the following: * RFC3530 (NFSv4) specifies that a reserved port# not be * required. * RFC2623 recommends that, if a reserved port# is checked for, * that there be a way to turn that off--> ifdef'd. */ #ifdef NFS_REQRSVPORT if (!nd->nd_repstat) { struct sockaddr_in *saddr; struct sockaddr_in6 *saddr6; saddr = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *); saddr6 = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in6 *); if (!(nd->nd_flag & ND_NFSV4) && ((saddr->sin_family == AF_INET && ntohs(saddr->sin_port) >= IPPORT_RESERVED) || (saddr6->sin6_family == AF_INET6 && ntohs(saddr6->sin6_port) >= IPPORT_RESERVED))) { vput(*vpp); nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); } } #endif /* NFS_REQRSVPORT */ /* * Check/setup credentials. */ if (!nd->nd_repstat) { nd->nd_saveduid = nd->nd_cred->cr_uid; nd->nd_repstat = nfsd_excred(nd, exp, credanon, nfsrv_checkwrongsec(nd, nextop, (*vpp)->v_type)); if (nd->nd_repstat) vput(*vpp); } if (credanon != NULL) crfree(credanon); if (nd->nd_repstat) { vn_finished_write(mpw); *vpp = NULL; } else if (mpp != NULL) { *mpp = mpw; } out: NFSEXITCODE2(0, nd); } /* * glue for fp. */ static int fp_getfvp(struct thread *p, int fd, struct file **fpp, struct vnode **vpp) { struct filedesc *fdp; struct file *fp; int error = 0; fdp = p->td_proc->p_fd; if (fd < 0 || fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd].fde_file) == NULL) { error = EBADF; goto out; } *fpp = fp; out: NFSEXITCODE(error); return (error); } /* * Called from nfssvc() to update the exports list. Just call * vfs_export(). This has to be done, since the v4 root fake fs isn't * in the mount list. */ int nfsrv_v4rootexport(void *argp, struct ucred *cred, struct thread *p) { struct nfsex_args *nfsexargp = (struct nfsex_args *)argp; int error = 0; struct nameidata nd; fhandle_t fh; error = vfs_export(NFSD_VNET(nfsv4root_mnt), &nfsexargp->export, false); if ((nfsexargp->export.ex_flags & MNT_DELEXPORT) != 0) NFSD_VNET(nfs_rootfhset) = 0; else if (error == 0) { if (nfsexargp->fspec == NULL) { error = EPERM; goto out; } /* * If fspec != NULL, this is the v4root path. */ 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) { NFSD_VNET(nfs_rootfh).nfsrvfh_len = NFSX_MYFH; NFSBCOPY((caddr_t)&fh, NFSD_VNET(nfs_rootfh).nfsrvfh_data, sizeof (fhandle_t)); NFSD_VNET(nfs_rootfhset) = 1; } } out: NFSEXITCODE(error); return (error); } /* * This function needs to test to see if the system is near its limit * for memory allocation via malloc() or mget() and return True iff * either of these resources are near their limit. * XXX (For now, this is just a stub.) */ int nfsrv_testmalloclimit = 0; int nfsrv_mallocmget_limit(void) { static int printmesg = 0; static int testval = 1; if (nfsrv_testmalloclimit && (testval++ % 1000) == 0) { if ((printmesg++ % 100) == 0) printf("nfsd: malloc/mget near limit\n"); return (1); } return (0); } /* * BSD specific initialization of a mount point. */ void nfsd_mntinit(void) { NFSD_LOCK(); if (NFSD_VNET(nfsrv_mntinited)) { NFSD_UNLOCK(); return; } NFSD_VNET(nfsrv_mntinited) = true; nfsrvd_init(0); NFSD_UNLOCK(); NFSD_VNET(nfsv4root_mnt) = malloc(sizeof(struct mount), M_TEMP, M_WAITOK | M_ZERO); NFSD_VNET(nfsv4root_mnt)->mnt_flag = (MNT_RDONLY | MNT_EXPORTED); mtx_init(&NFSD_VNET(nfsv4root_mnt)->mnt_mtx, "nfs4mnt", NULL, MTX_DEF); lockinit(&NFSD_VNET(nfsv4root_mnt)->mnt_explock, PVFS, "explock", 0, 0); TAILQ_INIT(&NFSD_VNET(nfsv4root_mnt)->mnt_nvnodelist); TAILQ_INIT(&NFSD_VNET(nfsv4root_mnt)->mnt_lazyvnodelist); NFSD_VNET(nfsv4root_mnt)->mnt_export = NULL; TAILQ_INIT(&NFSD_VNET(nfsv4root_opt)); TAILQ_INIT(&NFSD_VNET(nfsv4root_newopt)); NFSD_VNET(nfsv4root_mnt)->mnt_opt = &NFSD_VNET(nfsv4root_opt); NFSD_VNET(nfsv4root_mnt)->mnt_optnew = &NFSD_VNET(nfsv4root_newopt); NFSD_VNET(nfsv4root_mnt)->mnt_nvnodelistsize = 0; NFSD_VNET(nfsv4root_mnt)->mnt_lazyvnodelistsize = 0; callout_init(&NFSD_VNET(nfsd_callout), 1); nfsrvd_initcache(); nfsd_init(); } static void nfsd_timer(void *arg) { struct vnet *vnetp; vnetp = (struct vnet *)arg; NFSD_CURVNET_SET_QUIET(vnetp); nfsrv_servertimer(vnetp); callout_reset_sbt(&NFSD_VNET(nfsd_callout), SBT_1S, SBT_1S, nfsd_timer, arg, 0); NFSD_CURVNET_RESTORE(); } /* * Get a vnode for a file handle, without checking exports, etc. */ struct vnode * nfsvno_getvp(fhandle_t *fhp) { struct mount *mp; struct vnode *vp; int error; mp = vfs_busyfs(&fhp->fh_fsid); if (mp == NULL) return (NULL); error = VFS_FHTOVP(mp, &fhp->fh_fid, LK_EXCLUSIVE, &vp); vfs_unbusy(mp); if (error) return (NULL); return (vp); } /* * Do a local VOP_ADVLOCK(). */ int nfsvno_advlock(struct vnode *vp, int ftype, u_int64_t first, u_int64_t end, struct thread *td) { int error = 0; struct flock fl; u_int64_t tlen; if (nfsrv_dolocallocks == 0) goto out; ASSERT_VOP_UNLOCKED(vp, "nfsvno_advlock: vp locked"); fl.l_whence = SEEK_SET; fl.l_type = ftype; fl.l_start = (off_t)first; if (end == NFS64BITSSET) { fl.l_len = 0; } else { tlen = end - first; fl.l_len = (off_t)tlen; } /* * For FreeBSD8, the l_pid and l_sysid must be set to the same * values for all calls, so that all locks will be held by the * nfsd server. (The nfsd server handles conflicts between the * various clients.) * Since an NFSv4 lockowner is a ClientID plus an array of up to 1024 * bytes, so it can't be put in l_sysid. */ if (nfsv4_sysid == 0) nfsv4_sysid = nlm_acquire_next_sysid(); fl.l_pid = (pid_t)0; fl.l_sysid = (int)nfsv4_sysid; if (ftype == F_UNLCK) error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_UNLCK, &fl, (F_POSIX | F_REMOTE)); else error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_SETLK, &fl, (F_POSIX | F_REMOTE)); out: NFSEXITCODE(error); return (error); } /* * Check the nfsv4 root exports. */ int nfsvno_v4rootexport(struct nfsrv_descript *nd) { struct ucred *credanon; int error = 0, numsecflavor, secflavors[MAXSECFLAVORS], i; uint64_t exflags; error = vfs_stdcheckexp(NFSD_VNET(nfsv4root_mnt), nd->nd_nam, &exflags, &credanon, &numsecflavor, secflavors); if (error) { error = NFSERR_PROGUNAVAIL; goto out; } if (credanon != NULL) crfree(credanon); for (i = 0; i < numsecflavor; i++) { if (secflavors[i] == AUTH_SYS) nd->nd_flag |= ND_EXAUTHSYS; else if (secflavors[i] == RPCSEC_GSS_KRB5) nd->nd_flag |= ND_EXGSS; else if (secflavors[i] == RPCSEC_GSS_KRB5I) nd->nd_flag |= ND_EXGSSINTEGRITY; else if (secflavors[i] == RPCSEC_GSS_KRB5P) nd->nd_flag |= ND_EXGSSPRIVACY; } /* And set ND_EXxx flags for TLS. */ if ((exflags & MNT_EXTLS) != 0) { nd->nd_flag |= ND_EXTLS; if ((exflags & MNT_EXTLSCERT) != 0) nd->nd_flag |= ND_EXTLSCERT; if ((exflags & MNT_EXTLSCERTUSER) != 0) nd->nd_flag |= ND_EXTLSCERTUSER; } out: NFSEXITCODE(error); return (error); } /* * Nfs server pseudo system call for the nfsd's */ /* * MPSAFE */ static int nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap) { struct file *fp; struct nfsd_addsock_args sockarg; struct nfsd_nfsd_args nfsdarg; struct nfsd_nfsd_oargs onfsdarg; struct nfsd_pnfsd_args pnfsdarg; struct vnode *vp, *nvp, *curdvp; struct pnfsdsfile *pf; struct nfsdevice *ds, *fds; cap_rights_t rights; int buflen, error, ret; char *buf, *cp, *cp2, *cp3; char fname[PNFS_FILENAME_LEN + 1]; NFSD_CURVNET_SET(NFSD_TD_TO_VNET(td)); if (uap->flag & NFSSVC_NFSDADDSOCK) { error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg)); if (error) goto out; /* * Since we don't know what rights might be required, * pretend that we need them all. It is better to be too * careful than too reckless. */ error = fget(td, sockarg.sock, cap_rights_init_one(&rights, CAP_SOCK_SERVER), &fp); if (error != 0) goto out; if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); error = EPERM; goto out; } error = nfsrvd_addsock(fp); fdrop(fp, td); } else if (uap->flag & NFSSVC_NFSDNFSD) { if (uap->argp == NULL) { error = EINVAL; goto out; } if ((uap->flag & NFSSVC_NEWSTRUCT) == 0) { error = copyin(uap->argp, &onfsdarg, sizeof(onfsdarg)); if (error == 0) { nfsdarg.principal = onfsdarg.principal; nfsdarg.minthreads = onfsdarg.minthreads; nfsdarg.maxthreads = onfsdarg.maxthreads; nfsdarg.version = 1; nfsdarg.addr = NULL; nfsdarg.addrlen = 0; nfsdarg.dnshost = NULL; nfsdarg.dnshostlen = 0; nfsdarg.dspath = NULL; nfsdarg.dspathlen = 0; nfsdarg.mdspath = NULL; nfsdarg.mdspathlen = 0; nfsdarg.mirrorcnt = 1; } } else error = copyin(uap->argp, &nfsdarg, sizeof(nfsdarg)); if (error) goto out; if (nfsdarg.addrlen > 0 && nfsdarg.addrlen < 10000 && nfsdarg.dnshostlen > 0 && nfsdarg.dnshostlen < 10000 && nfsdarg.dspathlen > 0 && nfsdarg.dspathlen < 10000 && nfsdarg.mdspathlen > 0 && nfsdarg.mdspathlen < 10000 && nfsdarg.mirrorcnt >= 1 && nfsdarg.mirrorcnt <= NFSDEV_MAXMIRRORS && nfsdarg.addr != NULL && nfsdarg.dnshost != NULL && nfsdarg.dspath != NULL && nfsdarg.mdspath != NULL) { NFSD_DEBUG(1, "addrlen=%d dspathlen=%d dnslen=%d" " mdspathlen=%d mirrorcnt=%d\n", nfsdarg.addrlen, nfsdarg.dspathlen, nfsdarg.dnshostlen, nfsdarg.mdspathlen, nfsdarg.mirrorcnt); cp = malloc(nfsdarg.addrlen + 1, M_TEMP, M_WAITOK); error = copyin(nfsdarg.addr, cp, nfsdarg.addrlen); if (error != 0) { free(cp, M_TEMP); goto out; } cp[nfsdarg.addrlen] = '\0'; /* Ensure nul term. */ nfsdarg.addr = cp; cp = malloc(nfsdarg.dnshostlen + 1, M_TEMP, M_WAITOK); error = copyin(nfsdarg.dnshost, cp, nfsdarg.dnshostlen); if (error != 0) { free(nfsdarg.addr, M_TEMP); free(cp, M_TEMP); goto out; } cp[nfsdarg.dnshostlen] = '\0'; /* Ensure nul term. */ nfsdarg.dnshost = cp; cp = malloc(nfsdarg.dspathlen + 1, M_TEMP, M_WAITOK); error = copyin(nfsdarg.dspath, cp, nfsdarg.dspathlen); if (error != 0) { free(nfsdarg.addr, M_TEMP); free(nfsdarg.dnshost, M_TEMP); free(cp, M_TEMP); goto out; } cp[nfsdarg.dspathlen] = '\0'; /* Ensure nul term. */ nfsdarg.dspath = cp; cp = malloc(nfsdarg.mdspathlen + 1, M_TEMP, M_WAITOK); error = copyin(nfsdarg.mdspath, cp, nfsdarg.mdspathlen); if (error != 0) { free(nfsdarg.addr, M_TEMP); free(nfsdarg.dnshost, M_TEMP); free(nfsdarg.dspath, M_TEMP); free(cp, M_TEMP); goto out; } cp[nfsdarg.mdspathlen] = '\0'; /* Ensure nul term. */ nfsdarg.mdspath = cp; } else { nfsdarg.addr = NULL; nfsdarg.addrlen = 0; nfsdarg.dnshost = NULL; nfsdarg.dnshostlen = 0; nfsdarg.dspath = NULL; nfsdarg.dspathlen = 0; nfsdarg.mdspath = NULL; nfsdarg.mdspathlen = 0; nfsdarg.mirrorcnt = 1; } nfsd_timer(NFSD_TD_TO_VNET(td)); error = nfsrvd_nfsd(td, &nfsdarg); callout_drain(&NFSD_VNET(nfsd_callout)); free(nfsdarg.addr, M_TEMP); free(nfsdarg.dnshost, M_TEMP); free(nfsdarg.dspath, M_TEMP); free(nfsdarg.mdspath, M_TEMP); } else if (uap->flag & NFSSVC_PNFSDS) { error = copyin(uap->argp, &pnfsdarg, sizeof(pnfsdarg)); if (error == 0 && (pnfsdarg.op == PNFSDOP_DELDSSERVER || pnfsdarg.op == PNFSDOP_FORCEDELDS)) { cp = malloc(PATH_MAX + 1, M_TEMP, M_WAITOK); error = copyinstr(pnfsdarg.dspath, cp, PATH_MAX + 1, NULL); if (error == 0) error = nfsrv_deldsserver(pnfsdarg.op, cp, td); free(cp, M_TEMP); } else if (error == 0 && pnfsdarg.op == PNFSDOP_COPYMR) { cp = malloc(PATH_MAX + 1, M_TEMP, M_WAITOK); buflen = sizeof(*pf) * NFSDEV_MAXMIRRORS; buf = malloc(buflen, M_TEMP, M_WAITOK); error = copyinstr(pnfsdarg.mdspath, cp, PATH_MAX + 1, NULL); NFSD_DEBUG(4, "pnfsdcopymr cp mdspath=%d\n", error); if (error == 0 && pnfsdarg.dspath != NULL) { cp2 = malloc(PATH_MAX + 1, M_TEMP, M_WAITOK); error = copyinstr(pnfsdarg.dspath, cp2, PATH_MAX + 1, NULL); NFSD_DEBUG(4, "pnfsdcopymr cp dspath=%d\n", error); } else cp2 = NULL; if (error == 0 && pnfsdarg.curdspath != NULL) { cp3 = malloc(PATH_MAX + 1, M_TEMP, M_WAITOK); error = copyinstr(pnfsdarg.curdspath, cp3, PATH_MAX + 1, NULL); NFSD_DEBUG(4, "pnfsdcopymr cp curdspath=%d\n", error); } else cp3 = NULL; curdvp = NULL; fds = NULL; if (error == 0) error = nfsrv_mdscopymr(cp, cp2, cp3, buf, &buflen, fname, td, &vp, &nvp, &pf, &ds, &fds); NFSD_DEBUG(4, "nfsrv_mdscopymr=%d\n", error); if (error == 0) { if (pf->dsf_dir >= nfsrv_dsdirsize) { printf("copymr: dsdir out of range\n"); pf->dsf_dir = 0; } NFSD_DEBUG(4, "copymr: buflen=%d\n", buflen); error = nfsrv_copymr(vp, nvp, ds->nfsdev_dsdir[pf->dsf_dir], ds, pf, (struct pnfsdsfile *)buf, buflen / sizeof(*pf), td->td_ucred, td); vput(vp); vput(nvp); if (fds != NULL && error == 0) { curdvp = fds->nfsdev_dsdir[pf->dsf_dir]; ret = vn_lock(curdvp, LK_EXCLUSIVE); if (ret == 0) { nfsrv_dsremove(curdvp, fname, td->td_ucred, td); NFSVOPUNLOCK(curdvp); } } NFSD_DEBUG(4, "nfsrv_copymr=%d\n", error); } free(cp, M_TEMP); free(cp2, M_TEMP); free(cp3, M_TEMP); free(buf, M_TEMP); } } else { error = nfssvc_srvcall(td, uap, td->td_ucred); } out: NFSD_CURVNET_RESTORE(); NFSEXITCODE(error); return (error); } static int nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) { struct nfsex_args export; struct nfsex_oldargs oexp; struct file *fp = NULL; int stablefd, i, len; struct nfsd_clid adminrevoke; struct nfsd_dumplist dumplist; struct nfsd_dumpclients *dumpclients; struct nfsd_dumplocklist dumplocklist; struct nfsd_dumplocks *dumplocks; struct nameidata nd; vnode_t vp; int error = EINVAL, igotlock; struct proc *procp; gid_t *grps; if (uap->flag & NFSSVC_PUBLICFH) { NFSBZERO((caddr_t)&nfs_pubfh.nfsrvfh_data, sizeof (fhandle_t)); error = copyin(uap->argp, &nfs_pubfh.nfsrvfh_data, sizeof (fhandle_t)); if (!error) nfs_pubfhset = 1; } else if ((uap->flag & (NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT)) == (NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT)) { error = copyin(uap->argp,(caddr_t)&export, sizeof (struct nfsex_args)); if (!error) { grps = NULL; if (export.export.ex_ngroups > NGROUPS_MAX || export.export.ex_ngroups < 0) error = EINVAL; else if (export.export.ex_ngroups > 0) { grps = malloc(export.export.ex_ngroups * sizeof(gid_t), M_TEMP, M_WAITOK); error = copyin(export.export.ex_groups, grps, export.export.ex_ngroups * sizeof(gid_t)); export.export.ex_groups = grps; } else export.export.ex_groups = NULL; if (!error) error = nfsrv_v4rootexport(&export, cred, p); free(grps, M_TEMP); } } else if ((uap->flag & (NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT)) == NFSSVC_V4ROOTEXPORT) { error = copyin(uap->argp,(caddr_t)&oexp, sizeof (struct nfsex_oldargs)); if (!error) { memset(&export.export, 0, sizeof(export.export)); export.export.ex_flags = (uint64_t)oexp.export.ex_flags; export.export.ex_root = oexp.export.ex_root; export.export.ex_uid = oexp.export.ex_anon.cr_uid; export.export.ex_ngroups = oexp.export.ex_anon.cr_ngroups; export.export.ex_groups = NULL; if (export.export.ex_ngroups > XU_NGROUPS || export.export.ex_ngroups < 0) error = EINVAL; else if (export.export.ex_ngroups > 0) { export.export.ex_groups = malloc( export.export.ex_ngroups * sizeof(gid_t), M_TEMP, M_WAITOK); for (i = 0; i < export.export.ex_ngroups; i++) export.export.ex_groups[i] = oexp.export.ex_anon.cr_groups[i]; } export.export.ex_addr = oexp.export.ex_addr; export.export.ex_addrlen = oexp.export.ex_addrlen; export.export.ex_mask = oexp.export.ex_mask; export.export.ex_masklen = oexp.export.ex_masklen; export.export.ex_indexfile = oexp.export.ex_indexfile; export.export.ex_numsecflavors = oexp.export.ex_numsecflavors; if (export.export.ex_numsecflavors >= MAXSECFLAVORS || export.export.ex_numsecflavors < 0) error = EINVAL; else { for (i = 0; i < export.export.ex_numsecflavors; i++) export.export.ex_secflavors[i] = oexp.export.ex_secflavors[i]; } export.fspec = oexp.fspec; if (error == 0) error = nfsrv_v4rootexport(&export, cred, p); free(export.export.ex_groups, M_TEMP); } } else if (uap->flag & NFSSVC_NOPUBLICFH) { nfs_pubfhset = 0; error = 0; } else if (uap->flag & NFSSVC_STABLERESTART) { error = copyin(uap->argp, (caddr_t)&stablefd, sizeof (int)); if (!error) error = fp_getfvp(p, stablefd, &fp, &vp); if (!error && (NFSFPFLAG(fp) & (FREAD | FWRITE)) != (FREAD | FWRITE)) error = EBADF; if (!error && NFSD_VNET(nfsrv_numnfsd) != 0) error = ENXIO; if (!error) { NFSD_VNET(nfsrv_stablefirst).nsf_fp = fp; nfsrv_setupstable(p); } } else if (uap->flag & NFSSVC_ADMINREVOKE) { error = copyin(uap->argp, (caddr_t)&adminrevoke, sizeof (struct nfsd_clid)); if (!error) error = nfsrv_adminrevoke(&adminrevoke, p); } else if (uap->flag & NFSSVC_DUMPCLIENTS) { error = copyin(uap->argp, (caddr_t)&dumplist, sizeof (struct nfsd_dumplist)); if (!error && (dumplist.ndl_size < 1 || dumplist.ndl_size > NFSRV_MAXDUMPLIST)) error = EPERM; if (!error) { len = sizeof (struct nfsd_dumpclients) * dumplist.ndl_size; dumpclients = malloc(len, M_TEMP, M_WAITOK | M_ZERO); nfsrv_dumpclients(dumpclients, dumplist.ndl_size); error = copyout(dumpclients, dumplist.ndl_list, len); free(dumpclients, M_TEMP); } } else if (uap->flag & NFSSVC_DUMPLOCKS) { error = copyin(uap->argp, (caddr_t)&dumplocklist, sizeof (struct nfsd_dumplocklist)); if (!error && (dumplocklist.ndllck_size < 1 || dumplocklist.ndllck_size > NFSRV_MAXDUMPLIST)) error = EPERM; if (!error) error = nfsrv_lookupfilename(&nd, dumplocklist.ndllck_fname, p); if (!error) { len = sizeof (struct nfsd_dumplocks) * dumplocklist.ndllck_size; dumplocks = malloc(len, M_TEMP, M_WAITOK | M_ZERO); nfsrv_dumplocks(nd.ni_vp, dumplocks, dumplocklist.ndllck_size, p); vput(nd.ni_vp); error = copyout(dumplocks, dumplocklist.ndllck_list, len); free(dumplocks, M_TEMP); } } else if (uap->flag & NFSSVC_BACKUPSTABLE) { procp = p->td_proc; PROC_LOCK(procp); nfsd_master_pid = procp->p_pid; bcopy(procp->p_comm, nfsd_master_comm, MAXCOMLEN + 1); nfsd_master_start = procp->p_stats->p_start; NFSD_VNET(nfsd_master_proc) = procp; PROC_UNLOCK(procp); } else if ((uap->flag & NFSSVC_SUSPENDNFSD) != 0) { NFSLOCKV4ROOTMUTEX(); if (!NFSD_VNET(nfsrv_suspend_nfsd)) { /* Lock out all nfsd threads */ do { igotlock = nfsv4_lock( &NFSD_VNET(nfsd_suspend_lock), 1, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); } while (igotlock == 0 && !NFSD_VNET(nfsrv_suspend_nfsd)); NFSD_VNET(nfsrv_suspend_nfsd) = true; } NFSUNLOCKV4ROOTMUTEX(); error = 0; } else if ((uap->flag & NFSSVC_RESUMENFSD) != 0) { NFSLOCKV4ROOTMUTEX(); if (NFSD_VNET(nfsrv_suspend_nfsd)) { nfsv4_unlock(&NFSD_VNET(nfsd_suspend_lock), 0); NFSD_VNET(nfsrv_suspend_nfsd) = false; } NFSUNLOCKV4ROOTMUTEX(); error = 0; } NFSEXITCODE(error); return (error); } /* * Check exports. * Returns 0 if ok, 1 otherwise. */ int nfsvno_testexp(struct nfsrv_descript *nd, struct nfsexstuff *exp) { int i; if ((NFSVNO_EXTLS(exp) && (nd->nd_flag & ND_TLS) == 0) || (NFSVNO_EXTLSCERT(exp) && (nd->nd_flag & ND_TLSCERT) == 0) || (NFSVNO_EXTLSCERTUSER(exp) && (nd->nd_flag & ND_TLSCERTUSER) == 0)) { if ((nd->nd_flag & ND_NFSV4) != 0) return (NFSERR_WRONGSEC); #ifdef notnow /* There is currently no auth_stat for this. */ else if ((nd->nd_flag & ND_TLS) == 0) return (NFSERR_AUTHERR | AUTH_NEEDS_TLS); else return (NFSERR_AUTHERR | AUTH_NEEDS_TLS_MUTUAL_HOST); #endif else return (NFSERR_AUTHERR | AUTH_TOOWEAK); } /* * RFC2623 suggests that the NFSv3 Fsinfo RPC be allowed to use * AUTH_NONE or AUTH_SYS for file systems requiring RPCSEC_GSS. */ if ((nd->nd_flag & ND_NFSV3) != 0 && nd->nd_procnum == NFSPROC_FSINFO) return (0); /* * This seems odd, but allow the case where the security flavor * list is empty. This happens when NFSv4 is traversing non-exported * file systems. Exported file systems should always have a non-empty * security flavor list. */ if (exp->nes_numsecflavor == 0) return (0); for (i = 0; i < exp->nes_numsecflavor; i++) { /* * The tests for privacy and integrity must be first, * since ND_GSS is set for everything but AUTH_SYS. */ if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5P && (nd->nd_flag & ND_GSSPRIVACY)) return (0); if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5I && (nd->nd_flag & ND_GSSINTEGRITY)) return (0); if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5 && (nd->nd_flag & ND_GSS)) return (0); if (exp->nes_secflavors[i] == AUTH_SYS && (nd->nd_flag & ND_GSS) == 0) return (0); } if ((nd->nd_flag & ND_NFSV4) != 0) return (NFSERR_WRONGSEC); return (NFSERR_AUTHERR | AUTH_TOOWEAK); } /* * Calculate a hash value for the fid in a file handle. */ uint32_t nfsrv_hashfh(fhandle_t *fhp) { uint32_t hashval; hashval = hash32_buf(&fhp->fh_fid, sizeof(struct fid), 0); return (hashval); } /* * Calculate a hash value for the sessionid. */ uint32_t nfsrv_hashsessionid(uint8_t *sessionid) { uint32_t hashval; hashval = hash32_buf(sessionid, NFSX_V4SESSIONID, 0); return (hashval); } /* * Signal the userland master nfsd to backup the stable restart file. */ void nfsrv_backupstable(void) { struct proc *procp; if (NFSD_VNET(nfsd_master_proc) != NULL) { procp = pfind(nfsd_master_pid); /* Try to make sure it is the correct process. */ if (procp == NFSD_VNET(nfsd_master_proc) && procp->p_stats->p_start.tv_sec == nfsd_master_start.tv_sec && procp->p_stats->p_start.tv_usec == nfsd_master_start.tv_usec && strcmp(procp->p_comm, nfsd_master_comm) == 0) kern_psignal(procp, SIGUSR2); else NFSD_VNET(nfsd_master_proc) = NULL; if (procp != NULL) PROC_UNLOCK(procp); } } /* * Create a DS data file for nfsrv_pnfscreate(). Called for each mirror. * The arguments are in a structure, so that they can be passed through * taskqueue for a kernel process to execute this function. */ struct nfsrvdscreate { int done; int inprog; struct task tsk; struct ucred *tcred; struct vnode *dvp; NFSPROC_T *p; struct pnfsdsfile *pf; int err; fhandle_t fh; struct vattr va; struct vattr createva; }; int nfsrv_dscreate(struct vnode *dvp, struct vattr *vap, struct vattr *nvap, fhandle_t *fhp, struct pnfsdsfile *pf, struct pnfsdsattr *dsa, char *fnamep, struct ucred *tcred, NFSPROC_T *p, struct vnode **nvpp) { struct vnode *nvp; struct nameidata named; struct vattr va; char *bufp; u_long *hashp; struct nfsnode *np; struct nfsmount *nmp; int error; NFSNAMEICNDSET(&named.ni_cnd, tcred, CREATE, LOCKPARENT | LOCKLEAF | NOCACHE); nfsvno_setpathbuf(&named, &bufp, &hashp); named.ni_cnd.cn_lkflags = LK_EXCLUSIVE; named.ni_cnd.cn_nameptr = bufp; if (fnamep != NULL) { strlcpy(bufp, fnamep, PNFS_FILENAME_LEN + 1); named.ni_cnd.cn_namelen = strlen(bufp); } else named.ni_cnd.cn_namelen = nfsrv_putfhname(fhp, bufp); NFSD_DEBUG(4, "nfsrv_dscreate: dvp=%p fname=%s\n", dvp, bufp); /* Create the date file in the DS mount. */ error = NFSVOPLOCK(dvp, LK_EXCLUSIVE); if (error == 0) { error = VOP_CREATE(dvp, &nvp, &named.ni_cnd, vap); vref(dvp); VOP_VPUT_PAIR(dvp, error == 0 ? &nvp : NULL, false); if (error == 0) { /* Set the ownership of the file. */ error = VOP_SETATTR(nvp, nvap, tcred); NFSD_DEBUG(4, "nfsrv_dscreate:" " setattr-uid=%d\n", error); if (error != 0) vput(nvp); } if (error != 0) printf("pNFS: pnfscreate failed=%d\n", error); } else printf("pNFS: pnfscreate vnlock=%d\n", error); if (error == 0) { np = VTONFS(nvp); nmp = VFSTONFS(nvp->v_mount); if (strcmp(nvp->v_mount->mnt_vfc->vfc_name, "nfs") != 0 || nmp->nm_nam->sa_len > sizeof( struct sockaddr_in6) || np->n_fhp->nfh_len != NFSX_MYFH) { printf("Bad DS file: fstype=%s salen=%d" " fhlen=%d\n", nvp->v_mount->mnt_vfc->vfc_name, nmp->nm_nam->sa_len, np->n_fhp->nfh_len); error = ENOENT; } /* Set extattrs for the DS on the MDS file. */ if (error == 0) { if (dsa != NULL) { error = VOP_GETATTR(nvp, &va, tcred); if (error == 0) { dsa->dsa_filerev = va.va_filerev; dsa->dsa_size = va.va_size; dsa->dsa_atime = va.va_atime; dsa->dsa_mtime = va.va_mtime; dsa->dsa_bytes = va.va_bytes; } } if (error == 0) { NFSBCOPY(np->n_fhp->nfh_fh, &pf->dsf_fh, NFSX_MYFH); NFSBCOPY(nmp->nm_nam, &pf->dsf_sin, nmp->nm_nam->sa_len); NFSBCOPY(named.ni_cnd.cn_nameptr, pf->dsf_filename, sizeof(pf->dsf_filename)); } } else printf("pNFS: pnfscreate can't get DS" " attr=%d\n", error); if (nvpp != NULL && error == 0) *nvpp = nvp; else vput(nvp); } nfsvno_relpathbuf(&named); return (error); } /* * Start up the thread that will execute nfsrv_dscreate(). */ static void start_dscreate(void *arg, int pending) { struct nfsrvdscreate *dsc; dsc = (struct nfsrvdscreate *)arg; dsc->err = nfsrv_dscreate(dsc->dvp, &dsc->createva, &dsc->va, &dsc->fh, dsc->pf, NULL, NULL, dsc->tcred, dsc->p, NULL); dsc->done = 1; NFSD_DEBUG(4, "start_dscreate: err=%d\n", dsc->err); } /* * Create a pNFS data file on the Data Server(s). */ static void nfsrv_pnfscreate(struct vnode *vp, struct vattr *vap, struct ucred *cred, NFSPROC_T *p) { struct nfsrvdscreate *dsc, *tdsc = NULL; struct nfsdevice *ds, *tds, *fds; struct mount *mp; struct pnfsdsfile *pf, *tpf; struct pnfsdsattr dsattr; struct vattr va; struct vnode *dvp[NFSDEV_MAXMIRRORS]; struct nfsmount *nmp; fhandle_t fh; uid_t vauid; gid_t vagid; u_short vamode; struct ucred *tcred; int dsdir[NFSDEV_MAXMIRRORS], error, i, mirrorcnt, ret; int failpos, timo; /* Get a DS server directory in a round-robin order. */ mirrorcnt = 1; mp = vp->v_mount; ds = fds = NULL; NFSDDSLOCK(); /* * Search for the first entry that handles this MDS fs, but use the * first entry for all MDS fs's otherwise. */ TAILQ_FOREACH(tds, &nfsrv_devidhead, nfsdev_list) { if (tds->nfsdev_nmp != NULL) { if (tds->nfsdev_mdsisset == 0 && ds == NULL) ds = tds; else if (tds->nfsdev_mdsisset != 0 && fsidcmp( &mp->mnt_stat.f_fsid, &tds->nfsdev_mdsfsid) == 0) { ds = fds = tds; break; } } } if (ds == NULL) { NFSDDSUNLOCK(); NFSD_DEBUG(4, "nfsrv_pnfscreate: no srv\n"); return; } i = dsdir[0] = ds->nfsdev_nextdir; ds->nfsdev_nextdir = (ds->nfsdev_nextdir + 1) % nfsrv_dsdirsize; dvp[0] = ds->nfsdev_dsdir[i]; tds = TAILQ_NEXT(ds, nfsdev_list); if (nfsrv_maxpnfsmirror > 1 && tds != NULL) { TAILQ_FOREACH_FROM(tds, &nfsrv_devidhead, nfsdev_list) { if (tds->nfsdev_nmp != NULL && ((tds->nfsdev_mdsisset == 0 && fds == NULL) || (tds->nfsdev_mdsisset != 0 && fds != NULL && fsidcmp(&mp->mnt_stat.f_fsid, &tds->nfsdev_mdsfsid) == 0))) { dsdir[mirrorcnt] = i; dvp[mirrorcnt] = tds->nfsdev_dsdir[i]; mirrorcnt++; if (mirrorcnt >= nfsrv_maxpnfsmirror) break; } } } /* Put at end of list to implement round-robin usage. */ TAILQ_REMOVE(&nfsrv_devidhead, ds, nfsdev_list); TAILQ_INSERT_TAIL(&nfsrv_devidhead, ds, nfsdev_list); NFSDDSUNLOCK(); dsc = NULL; if (mirrorcnt > 1) tdsc = dsc = malloc(sizeof(*dsc) * (mirrorcnt - 1), M_TEMP, M_WAITOK | M_ZERO); tpf = pf = malloc(sizeof(*pf) * nfsrv_maxpnfsmirror, M_TEMP, M_WAITOK | M_ZERO); error = nfsvno_getfh(vp, &fh, p); if (error == 0) error = VOP_GETATTR(vp, &va, cred); if (error == 0) { /* Set the attributes for "vp" to Setattr the DS vp. */ vauid = va.va_uid; vagid = va.va_gid; vamode = va.va_mode; VATTR_NULL(&va); va.va_uid = vauid; va.va_gid = vagid; va.va_mode = vamode; va.va_size = 0; } else printf("pNFS: pnfscreate getfh+attr=%d\n", error); NFSD_DEBUG(4, "nfsrv_pnfscreate: cruid=%d crgid=%d\n", cred->cr_uid, cred->cr_gid); /* Make data file name based on FH. */ tcred = newnfs_getcred(); /* * Create the file on each DS mirror, using kernel process(es) for the * additional mirrors. */ failpos = -1; for (i = 0; i < mirrorcnt - 1 && error == 0; i++, tpf++, tdsc++) { tpf->dsf_dir = dsdir[i]; tdsc->tcred = tcred; tdsc->p = p; tdsc->pf = tpf; tdsc->createva = *vap; NFSBCOPY(&fh, &tdsc->fh, sizeof(fh)); tdsc->va = va; tdsc->dvp = dvp[i]; tdsc->done = 0; tdsc->inprog = 0; tdsc->err = 0; ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_dscreate, tdsc); NFSD_DEBUG(4, "nfsrv_pnfscreate: nfs_pnfsio=%d\n", ret); } if (ret != 0) { ret = nfsrv_dscreate(dvp[i], vap, &va, &fh, tpf, NULL, NULL, tcred, p, NULL); if (ret != 0) { KASSERT(error == 0, ("nfsrv_dscreate err=%d", error)); if (failpos == -1 && nfsds_failerr(ret)) failpos = i; else error = ret; } } } if (error == 0) { tpf->dsf_dir = dsdir[mirrorcnt - 1]; error = nfsrv_dscreate(dvp[mirrorcnt - 1], vap, &va, &fh, tpf, &dsattr, NULL, tcred, p, NULL); if (failpos == -1 && mirrorcnt > 1 && nfsds_failerr(error)) { failpos = mirrorcnt - 1; error = 0; } } timo = hz / 50; /* Wait for 20msec. */ if (timo < 1) timo = 1; /* Wait for kernel task(s) to complete. */ for (tdsc = dsc, i = 0; i < mirrorcnt - 1; i++, tdsc++) { while (tdsc->inprog != 0 && tdsc->done == 0) tsleep(&tdsc->tsk, PVFS, "srvdcr", timo); if (tdsc->err != 0) { if (failpos == -1 && nfsds_failerr(tdsc->err)) failpos = i; else if (error == 0) error = tdsc->err; } } /* * If failpos has been set, that mirror has failed, so it needs * to be disabled. */ if (failpos >= 0) { nmp = VFSTONFS(dvp[failpos]->v_mount); NFSLOCKMNT(nmp); if ((nmp->nm_privflag & (NFSMNTP_FORCEDISM | NFSMNTP_CANCELRPCS)) == 0) { nmp->nm_privflag |= NFSMNTP_CANCELRPCS; NFSUNLOCKMNT(nmp); ds = nfsrv_deldsnmp(PNFSDOP_DELDSSERVER, nmp, p); NFSD_DEBUG(4, "dscreatfail fail=%d ds=%p\n", failpos, ds); if (ds != NULL) nfsrv_killrpcs(nmp); NFSLOCKMNT(nmp); nmp->nm_privflag &= ~NFSMNTP_CANCELRPCS; wakeup(nmp); } NFSUNLOCKMNT(nmp); } NFSFREECRED(tcred); if (error == 0) { ASSERT_VOP_ELOCKED(vp, "nfsrv_pnfscreate vp"); NFSD_DEBUG(4, "nfsrv_pnfscreate: mirrorcnt=%d maxmirror=%d\n", mirrorcnt, nfsrv_maxpnfsmirror); /* * For all mirrors that couldn't be created, fill in the * *pf structure, but with an IP address == 0.0.0.0. */ tpf = pf + mirrorcnt; for (i = mirrorcnt; i < nfsrv_maxpnfsmirror; i++, tpf++) { *tpf = *pf; tpf->dsf_sin.sin_family = AF_INET; tpf->dsf_sin.sin_len = sizeof(struct sockaddr_in); tpf->dsf_sin.sin_addr.s_addr = 0; tpf->dsf_sin.sin_port = 0; } error = vn_extattr_set(vp, IO_NODELOCKED, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile", sizeof(*pf) * nfsrv_maxpnfsmirror, (char *)pf, p); if (error == 0) error = vn_extattr_set(vp, IO_NODELOCKED, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsattr", sizeof(dsattr), (char *)&dsattr, p); if (error != 0) printf("pNFS: pnfscreate setextattr=%d\n", error); } else printf("pNFS: pnfscreate=%d\n", error); free(pf, M_TEMP); free(dsc, M_TEMP); } /* * Get the information needed to remove the pNFS Data Server file from the * Metadata file. Upon success, ddvp is set non-NULL to the locked * DS directory vnode. The caller must unlock *ddvp when done with it. */ static void nfsrv_pnfsremovesetup(struct vnode *vp, NFSPROC_T *p, struct vnode **dvpp, int *mirrorcntp, char *fname, fhandle_t *fhp) { struct vattr va; struct ucred *tcred; char *buf; int buflen, error; dvpp[0] = NULL; /* If not an exported regular file or not a pNFS server, just return. */ if (vp->v_type != VREG || (vp->v_mount->mnt_flag & MNT_EXPORTED) == 0 || nfsrv_devidcnt == 0) return; /* Check to see if this is the last hard link. */ tcred = newnfs_getcred(); error = VOP_GETATTR(vp, &va, tcred); NFSFREECRED(tcred); if (error != 0) { printf("pNFS: nfsrv_pnfsremovesetup getattr=%d\n", error); return; } if (va.va_nlink > 1) return; error = nfsvno_getfh(vp, fhp, p); if (error != 0) { printf("pNFS: nfsrv_pnfsremovesetup getfh=%d\n", error); return; } buflen = 1024; buf = malloc(buflen, M_TEMP, M_WAITOK); /* Get the directory vnode for the DS mount and the file handle. */ error = nfsrv_dsgetsockmnt(vp, 0, buf, &buflen, mirrorcntp, p, dvpp, NULL, NULL, fname, NULL, NULL, NULL, NULL, NULL); free(buf, M_TEMP); if (error != 0) printf("pNFS: nfsrv_pnfsremovesetup getsockmnt=%d\n", error); } /* * Remove a DS data file for nfsrv_pnfsremove(). Called for each mirror. * The arguments are in a structure, so that they can be passed through * taskqueue for a kernel process to execute this function. */ struct nfsrvdsremove { int done; int inprog; struct task tsk; struct ucred *tcred; struct vnode *dvp; NFSPROC_T *p; int err; char fname[PNFS_FILENAME_LEN + 1]; }; static int nfsrv_dsremove(struct vnode *dvp, char *fname, struct ucred *tcred, NFSPROC_T *p) { struct nameidata named; struct vnode *nvp; char *bufp; u_long *hashp; int error; error = NFSVOPLOCK(dvp, LK_EXCLUSIVE); if (error != 0) return (error); named.ni_cnd.cn_nameiop = DELETE; named.ni_cnd.cn_lkflags = LK_EXCLUSIVE | LK_RETRY; named.ni_cnd.cn_cred = tcred; named.ni_cnd.cn_flags = ISLASTCN | LOCKPARENT | LOCKLEAF; nfsvno_setpathbuf(&named, &bufp, &hashp); named.ni_cnd.cn_nameptr = bufp; named.ni_cnd.cn_namelen = strlen(fname); strlcpy(bufp, fname, NAME_MAX); NFSD_DEBUG(4, "nfsrv_pnfsremove: filename=%s\n", bufp); error = VOP_LOOKUP(dvp, &nvp, &named.ni_cnd); NFSD_DEBUG(4, "nfsrv_pnfsremove: aft LOOKUP=%d\n", error); if (error == 0) { error = VOP_REMOVE(dvp, nvp, &named.ni_cnd); vput(nvp); } NFSVOPUNLOCK(dvp); nfsvno_relpathbuf(&named); if (error != 0) printf("pNFS: nfsrv_pnfsremove failed=%d\n", error); return (error); } /* * Start up the thread that will execute nfsrv_dsremove(). */ static void start_dsremove(void *arg, int pending) { struct nfsrvdsremove *dsrm; dsrm = (struct nfsrvdsremove *)arg; dsrm->err = nfsrv_dsremove(dsrm->dvp, dsrm->fname, dsrm->tcred, dsrm->p); dsrm->done = 1; NFSD_DEBUG(4, "start_dsremove: err=%d\n", dsrm->err); } /* * Remove a pNFS data file from a Data Server. * nfsrv_pnfsremovesetup() must have been called before the MDS file was * removed to set up the dvp and fill in the FH. */ static void nfsrv_pnfsremove(struct vnode **dvp, int mirrorcnt, char *fname, fhandle_t *fhp, NFSPROC_T *p) { struct ucred *tcred; struct nfsrvdsremove *dsrm, *tdsrm; struct nfsdevice *ds; struct nfsmount *nmp; int failpos, i, ret, timo; tcred = newnfs_getcred(); dsrm = NULL; if (mirrorcnt > 1) dsrm = malloc(sizeof(*dsrm) * mirrorcnt - 1, M_TEMP, M_WAITOK); /* * Remove the file on each DS mirror, using kernel process(es) for the * additional mirrors. */ failpos = -1; for (tdsrm = dsrm, i = 0; i < mirrorcnt - 1; i++, tdsrm++) { tdsrm->tcred = tcred; tdsrm->p = p; tdsrm->dvp = dvp[i]; strlcpy(tdsrm->fname, fname, PNFS_FILENAME_LEN + 1); tdsrm->inprog = 0; tdsrm->done = 0; tdsrm->err = 0; ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_dsremove, tdsrm); NFSD_DEBUG(4, "nfsrv_pnfsremove: nfs_pnfsio=%d\n", ret); } if (ret != 0) { ret = nfsrv_dsremove(dvp[i], fname, tcred, p); if (failpos == -1 && nfsds_failerr(ret)) failpos = i; } } ret = nfsrv_dsremove(dvp[mirrorcnt - 1], fname, tcred, p); if (failpos == -1 && mirrorcnt > 1 && nfsds_failerr(ret)) failpos = mirrorcnt - 1; timo = hz / 50; /* Wait for 20msec. */ if (timo < 1) timo = 1; /* Wait for kernel task(s) to complete. */ for (tdsrm = dsrm, i = 0; i < mirrorcnt - 1; i++, tdsrm++) { while (tdsrm->inprog != 0 && tdsrm->done == 0) tsleep(&tdsrm->tsk, PVFS, "srvdsrm", timo); if (failpos == -1 && nfsds_failerr(tdsrm->err)) failpos = i; } /* * If failpos has been set, that mirror has failed, so it needs * to be disabled. */ if (failpos >= 0) { nmp = VFSTONFS(dvp[failpos]->v_mount); NFSLOCKMNT(nmp); if ((nmp->nm_privflag & (NFSMNTP_FORCEDISM | NFSMNTP_CANCELRPCS)) == 0) { nmp->nm_privflag |= NFSMNTP_CANCELRPCS; NFSUNLOCKMNT(nmp); ds = nfsrv_deldsnmp(PNFSDOP_DELDSSERVER, nmp, p); NFSD_DEBUG(4, "dsremovefail fail=%d ds=%p\n", failpos, ds); if (ds != NULL) nfsrv_killrpcs(nmp); NFSLOCKMNT(nmp); nmp->nm_privflag &= ~NFSMNTP_CANCELRPCS; wakeup(nmp); } NFSUNLOCKMNT(nmp); } /* Get rid all layouts for the file. */ nfsrv_freefilelayouts(fhp); NFSFREECRED(tcred); free(dsrm, M_TEMP); } /* * Generate a file name based on the file handle and put it in *bufp. * Return the number of bytes generated. */ static int nfsrv_putfhname(fhandle_t *fhp, char *bufp) { int i; uint8_t *cp; const uint8_t *hexdigits = "0123456789abcdef"; cp = (uint8_t *)fhp; for (i = 0; i < sizeof(*fhp); i++) { bufp[2 * i] = hexdigits[(*cp >> 4) & 0xf]; bufp[2 * i + 1] = hexdigits[*cp++ & 0xf]; } bufp[2 * i] = '\0'; return (2 * i); } /* * Update the Metadata file's attributes from the DS file when a Read/Write * layout is returned. * Basically just call nfsrv_proxyds() with procedure == NFSPROC_LAYOUTRETURN * so that it does a nfsrv_getattrdsrpc() and nfsrv_setextattr() on the DS file. */ int nfsrv_updatemdsattr(struct vnode *vp, struct nfsvattr *nap, NFSPROC_T *p) { struct ucred *tcred; int error; /* Do this as root so that it won't fail with EACCES. */ tcred = newnfs_getcred(); error = nfsrv_proxyds(vp, 0, 0, tcred, p, NFSPROC_LAYOUTRETURN, NULL, NULL, NULL, nap, NULL, NULL, 0, NULL); NFSFREECRED(tcred); return (error); } /* * Set the NFSv4 ACL on the DS file to the same ACL as the MDS file. */ static int nfsrv_dssetacl(struct vnode *vp, struct acl *aclp, struct ucred *cred, NFSPROC_T *p) { int error; error = nfsrv_proxyds(vp, 0, 0, cred, p, NFSPROC_SETACL, NULL, NULL, NULL, NULL, aclp, NULL, 0, NULL); return (error); } static int nfsrv_proxyds(struct vnode *vp, off_t off, int cnt, struct ucred *cred, struct thread *p, int ioproc, struct mbuf **mpp, char *cp, struct mbuf **mpp2, struct nfsvattr *nap, struct acl *aclp, off_t *offp, int content, bool *eofp) { struct nfsmount *nmp[NFSDEV_MAXMIRRORS], *failnmp; fhandle_t fh[NFSDEV_MAXMIRRORS]; struct vnode *dvp[NFSDEV_MAXMIRRORS]; struct nfsdevice *ds; struct pnfsdsattr dsattr; struct opnfsdsattr odsattr; char *buf; int buflen, error, failpos, i, mirrorcnt, origmircnt, trycnt; NFSD_DEBUG(4, "in nfsrv_proxyds\n"); /* * If not a regular file, not exported or not a pNFS server, * just return ENOENT. */ if (vp->v_type != VREG || (vp->v_mount->mnt_flag & MNT_EXPORTED) == 0 || nfsrv_devidcnt == 0) return (ENOENT); buflen = 1024; buf = malloc(buflen, M_TEMP, M_WAITOK); error = 0; /* * For Getattr, get the Change attribute (va_filerev) and size (va_size) * from the MetaData file's extended attribute. */ if (ioproc == NFSPROC_GETATTR) { error = vn_extattr_get(vp, IO_NODELOCKED, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsattr", &buflen, buf, p); if (error == 0) { if (buflen == sizeof(odsattr)) { NFSBCOPY(buf, &odsattr, buflen); nap->na_filerev = odsattr.dsa_filerev; nap->na_size = odsattr.dsa_size; nap->na_atime = odsattr.dsa_atime; nap->na_mtime = odsattr.dsa_mtime; /* * Fake na_bytes by rounding up na_size. * Since we don't know the block size, just * use BLKDEV_IOSIZE. */ nap->na_bytes = (odsattr.dsa_size + BLKDEV_IOSIZE - 1) & ~(BLKDEV_IOSIZE - 1); } else if (buflen == sizeof(dsattr)) { NFSBCOPY(buf, &dsattr, buflen); nap->na_filerev = dsattr.dsa_filerev; nap->na_size = dsattr.dsa_size; nap->na_atime = dsattr.dsa_atime; nap->na_mtime = dsattr.dsa_mtime; nap->na_bytes = dsattr.dsa_bytes; } else error = ENXIO; } if (error == 0) { /* * If nfsrv_pnfsgetdsattr is 0 or nfsrv_checkdsattr() * returns 0, just return now. nfsrv_checkdsattr() * returns 0 if there is no Read/Write layout * plus either an Open/Write_access or Write * delegation issued to a client for the file. */ if (nfsrv_pnfsgetdsattr == 0 || nfsrv_checkdsattr(vp, p) == 0) { free(buf, M_TEMP); return (error); } } /* * Clear ENOATTR so the code below will attempt to do a * nfsrv_getattrdsrpc() to get the attributes and (re)create * the extended attribute. */ if (error == ENOATTR) error = 0; } origmircnt = -1; trycnt = 0; tryagain: if (error == 0) { buflen = 1024; if (ioproc == NFSPROC_READDS && NFSVOPISLOCKED(vp) == LK_EXCLUSIVE) printf("nfsrv_proxyds: Readds vp exclusively locked\n"); error = nfsrv_dsgetsockmnt(vp, LK_SHARED, buf, &buflen, &mirrorcnt, p, dvp, fh, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (error == 0) { for (i = 0; i < mirrorcnt; i++) nmp[i] = VFSTONFS(dvp[i]->v_mount); } else printf("pNFS: proxy getextattr sockaddr=%d\n", error); } else printf("pNFS: nfsrv_dsgetsockmnt=%d\n", error); if (error == 0) { failpos = -1; if (origmircnt == -1) origmircnt = mirrorcnt; /* * If failpos is set to a mirror#, then that mirror has * failed and will be disabled. For Read, Getattr and Seek, the * function only tries one mirror, so if that mirror has * failed, it will need to be retried. As such, increment * tryitagain for these cases. * For Write, Setattr and Setacl, the function tries all * mirrors and will not return an error for the case where * one mirror has failed. For these cases, the functioning * mirror(s) will have been modified, so a retry isn't * necessary. These functions will set failpos for the * failed mirror#. */ if (ioproc == NFSPROC_READDS) { error = nfsrv_readdsrpc(fh, off, cnt, cred, p, nmp[0], mpp, mpp2); if (nfsds_failerr(error) && mirrorcnt > 1) { /* * Setting failpos will cause the mirror * to be disabled and then a retry of this * read is required. */ failpos = 0; error = 0; trycnt++; } } else if (ioproc == NFSPROC_WRITEDS) error = nfsrv_writedsrpc(fh, off, cnt, cred, p, vp, &nmp[0], mirrorcnt, mpp, cp, &failpos); else if (ioproc == NFSPROC_SETATTR) error = nfsrv_setattrdsrpc(fh, cred, p, vp, &nmp[0], mirrorcnt, nap, &failpos); else if (ioproc == NFSPROC_SETACL) error = nfsrv_setacldsrpc(fh, cred, p, vp, &nmp[0], mirrorcnt, aclp, &failpos); else if (ioproc == NFSPROC_SEEKDS) { error = nfsrv_seekdsrpc(fh, offp, content, eofp, cred, p, nmp[0]); if (nfsds_failerr(error) && mirrorcnt > 1) { /* * Setting failpos will cause the mirror * to be disabled and then a retry of this * read is required. */ failpos = 0; error = 0; trycnt++; } } else if (ioproc == NFSPROC_ALLOCATE) error = nfsrv_allocatedsrpc(fh, off, *offp, cred, p, vp, &nmp[0], mirrorcnt, &failpos); else if (ioproc == NFSPROC_DEALLOCATE) error = nfsrv_deallocatedsrpc(fh, off, *offp, cred, p, vp, &nmp[0], mirrorcnt, &failpos); else { error = nfsrv_getattrdsrpc(&fh[mirrorcnt - 1], cred, p, vp, nmp[mirrorcnt - 1], nap); if (nfsds_failerr(error) && mirrorcnt > 1) { /* * Setting failpos will cause the mirror * to be disabled and then a retry of this * getattr is required. */ failpos = mirrorcnt - 1; error = 0; trycnt++; } } ds = NULL; if (failpos >= 0) { failnmp = nmp[failpos]; NFSLOCKMNT(failnmp); if ((failnmp->nm_privflag & (NFSMNTP_FORCEDISM | NFSMNTP_CANCELRPCS)) == 0) { failnmp->nm_privflag |= NFSMNTP_CANCELRPCS; NFSUNLOCKMNT(failnmp); ds = nfsrv_deldsnmp(PNFSDOP_DELDSSERVER, failnmp, p); NFSD_DEBUG(4, "dsldsnmp fail=%d ds=%p\n", failpos, ds); if (ds != NULL) nfsrv_killrpcs(failnmp); NFSLOCKMNT(failnmp); failnmp->nm_privflag &= ~NFSMNTP_CANCELRPCS; wakeup(failnmp); } NFSUNLOCKMNT(failnmp); } for (i = 0; i < mirrorcnt; i++) NFSVOPUNLOCK(dvp[i]); NFSD_DEBUG(4, "nfsrv_proxyds: aft RPC=%d trya=%d\n", error, trycnt); /* Try the Read/Getattr again if a mirror was deleted. */ if (ds != NULL && trycnt > 0 && trycnt < origmircnt) goto tryagain; } else { /* Return ENOENT for any Extended Attribute error. */ error = ENOENT; } free(buf, M_TEMP); NFSD_DEBUG(4, "nfsrv_proxyds: error=%d\n", error); return (error); } /* * Get the DS mount point, fh and directory from the "pnfsd.dsfile" extended * attribute. * newnmpp - If it points to a non-NULL nmp, that is the destination and needs * to be checked. If it points to a NULL nmp, then it returns * a suitable destination. * curnmp - If non-NULL, it is the source mount for the copy. */ int nfsrv_dsgetsockmnt(struct vnode *vp, int lktype, char *buf, int *buflenp, int *mirrorcntp, NFSPROC_T *p, struct vnode **dvpp, fhandle_t *fhp, char *devid, char *fnamep, struct vnode **nvpp, struct nfsmount **newnmpp, struct nfsmount *curnmp, int *ippos, int *dsdirp) { struct vnode *dvp, *nvp = NULL, **tdvpp; struct mount *mp; struct nfsmount *nmp, *newnmp; struct sockaddr *sad; struct sockaddr_in *sin; struct nfsdevice *ds, *tds, *fndds; struct pnfsdsfile *pf; uint32_t dsdir; int error, fhiszero, fnd, gotone, i, mirrorcnt; ASSERT_VOP_LOCKED(vp, "nfsrv_dsgetsockmnt vp"); *mirrorcntp = 1; tdvpp = dvpp; if (nvpp != NULL) *nvpp = NULL; if (dvpp != NULL) *dvpp = NULL; if (ippos != NULL) *ippos = -1; if (newnmpp != NULL) newnmp = *newnmpp; else newnmp = NULL; mp = vp->v_mount; error = vn_extattr_get(vp, IO_NODELOCKED, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile", buflenp, buf, p); mirrorcnt = *buflenp / sizeof(*pf); if (error == 0 && (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS || *buflenp != sizeof(*pf) * mirrorcnt)) error = ENOATTR; pf = (struct pnfsdsfile *)buf; /* If curnmp != NULL, check for a match in the mirror list. */ if (curnmp != NULL && error == 0) { fnd = 0; for (i = 0; i < mirrorcnt; i++, pf++) { sad = (struct sockaddr *)&pf->dsf_sin; if (nfsaddr2_match(sad, curnmp->nm_nam)) { if (ippos != NULL) *ippos = i; fnd = 1; break; } } if (fnd == 0) error = ENXIO; } gotone = 0; pf = (struct pnfsdsfile *)buf; NFSD_DEBUG(4, "nfsrv_dsgetsockmnt: mirrorcnt=%d err=%d\n", mirrorcnt, error); for (i = 0; i < mirrorcnt && error == 0; i++, pf++) { fhiszero = 0; sad = (struct sockaddr *)&pf->dsf_sin; sin = &pf->dsf_sin; dsdir = pf->dsf_dir; if (dsdir >= nfsrv_dsdirsize) { printf("nfsrv_dsgetsockmnt: dsdir=%d\n", dsdir); error = ENOATTR; } else if (nvpp != NULL && newnmp != NULL && nfsaddr2_match(sad, newnmp->nm_nam)) error = EEXIST; if (error == 0) { if (ippos != NULL && curnmp == NULL && sad->sa_family == AF_INET && sin->sin_addr.s_addr == 0) *ippos = i; if (NFSBCMP(&zerofh, &pf->dsf_fh, sizeof(zerofh)) == 0) fhiszero = 1; /* Use the socket address to find the mount point. */ fndds = NULL; NFSDDSLOCK(); /* Find a match for the IP address. */ TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) { if (ds->nfsdev_nmp != NULL) { dvp = ds->nfsdev_dvp; nmp = VFSTONFS(dvp->v_mount); if (nmp != ds->nfsdev_nmp) printf("different2 nmp %p %p\n", nmp, ds->nfsdev_nmp); if (nfsaddr2_match(sad, nmp->nm_nam)) { fndds = ds; break; } } } if (fndds != NULL && newnmpp != NULL && newnmp == NULL) { /* Search for a place to make a mirror copy. */ TAILQ_FOREACH(tds, &nfsrv_devidhead, nfsdev_list) { if (tds->nfsdev_nmp != NULL && fndds != tds && ((tds->nfsdev_mdsisset == 0 && fndds->nfsdev_mdsisset == 0) || (tds->nfsdev_mdsisset != 0 && fndds->nfsdev_mdsisset != 0 && fsidcmp(&tds->nfsdev_mdsfsid, &mp->mnt_stat.f_fsid) == 0))) { *newnmpp = tds->nfsdev_nmp; break; } } if (tds != NULL) { /* * Move this entry to the end of the * list, so it won't be selected as * easily the next time. */ TAILQ_REMOVE(&nfsrv_devidhead, tds, nfsdev_list); TAILQ_INSERT_TAIL(&nfsrv_devidhead, tds, nfsdev_list); } } NFSDDSUNLOCK(); if (fndds != NULL) { dvp = fndds->nfsdev_dsdir[dsdir]; if (lktype != 0 || fhiszero != 0 || (nvpp != NULL && *nvpp == NULL)) { if (fhiszero != 0) error = vn_lock(dvp, LK_EXCLUSIVE); else if (lktype != 0) error = vn_lock(dvp, lktype); else error = vn_lock(dvp, LK_SHARED); /* * If the file handle is all 0's, try to * do a Lookup against the DS to acquire * it. * If dvpp == NULL or the Lookup fails, * unlock dvp after the call. */ if (error == 0 && (fhiszero != 0 || (nvpp != NULL && *nvpp == NULL))) { error = nfsrv_pnfslookupds(vp, dvp, pf, &nvp, p); if (error == 0) { if (fhiszero != 0) nfsrv_pnfssetfh( vp, pf, devid, fnamep, nvp, p); if (nvpp != NULL && *nvpp == NULL) { *nvpp = nvp; *dsdirp = dsdir; } else vput(nvp); } if (error != 0 || lktype == 0) NFSVOPUNLOCK(dvp); } } if (error == 0) { gotone++; NFSD_DEBUG(4, "gotone=%d\n", gotone); if (devid != NULL) { NFSBCOPY(fndds->nfsdev_deviceid, devid, NFSX_V4DEVICEID); devid += NFSX_V4DEVICEID; } if (dvpp != NULL) *tdvpp++ = dvp; if (fhp != NULL) NFSBCOPY(&pf->dsf_fh, fhp++, NFSX_MYFH); if (fnamep != NULL && gotone == 1) strlcpy(fnamep, pf->dsf_filename, sizeof(pf->dsf_filename)); } else NFSD_DEBUG(4, "nfsrv_dsgetsockmnt " "err=%d\n", error); } } } if (error == 0 && gotone == 0) error = ENOENT; NFSD_DEBUG(4, "eo nfsrv_dsgetsockmnt: gotone=%d err=%d\n", gotone, error); if (error == 0) *mirrorcntp = gotone; else { if (gotone > 0 && dvpp != NULL) { /* * If the error didn't occur on the first one and * dvpp != NULL, the one(s) prior to the failure will * have locked dvp's that need to be unlocked. */ for (i = 0; i < gotone; i++) { NFSVOPUNLOCK(*dvpp); *dvpp++ = NULL; } } /* * If it found the vnode to be copied from before a failure, * it needs to be vput()'d. */ if (nvpp != NULL && *nvpp != NULL) { vput(*nvpp); *nvpp = NULL; } } return (error); } /* * Set the extended attribute for the Change attribute. */ static int nfsrv_setextattr(struct vnode *vp, struct nfsvattr *nap, NFSPROC_T *p) { struct pnfsdsattr dsattr; int error; ASSERT_VOP_ELOCKED(vp, "nfsrv_setextattr vp"); dsattr.dsa_filerev = nap->na_filerev; dsattr.dsa_size = nap->na_size; dsattr.dsa_atime = nap->na_atime; dsattr.dsa_mtime = nap->na_mtime; dsattr.dsa_bytes = nap->na_bytes; error = vn_extattr_set(vp, IO_NODELOCKED, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsattr", sizeof(dsattr), (char *)&dsattr, p); if (error != 0) printf("pNFS: setextattr=%d\n", error); return (error); } static int nfsrv_readdsrpc(fhandle_t *fhp, off_t off, int len, struct ucred *cred, NFSPROC_T *p, struct nfsmount *nmp, struct mbuf **mpp, struct mbuf **mpendp) { uint32_t *tl; struct nfsrv_descript *nd; nfsv4stateid_t st; struct mbuf *m, *m2; int error = 0, retlen, tlen, trimlen; NFSD_DEBUG(4, "in nfsrv_readdsrpc\n"); nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO); *mpp = NULL; /* * Use a stateid where other is an alternating 01010 pattern and * seqid is 0xffffffff. This value is not defined as special by * the RFC and is used by the FreeBSD NFS server to indicate an * MDS->DS proxy operation. */ st.other[0] = 0x55555555; st.other[1] = 0x55555555; st.other[2] = 0x55555555; st.seqid = 0xffffffff; nfscl_reqstart(nd, NFSPROC_READDS, nmp, (u_int8_t *)fhp, sizeof(*fhp), NULL, NULL, 0, 0, cred); nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); txdr_hyper(off, tl); *(tl + 2) = txdr_unsigned(len); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) { free(nd, M_TEMP); return (error); } if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_STRSIZ(retlen, len); if (retlen > 0) { /* Trim off the pre-data XDR from the mbuf chain. */ m = nd->nd_mrep; while (m != NULL && m != nd->nd_md) { if (m->m_next == nd->nd_md) { m->m_next = NULL; m_freem(nd->nd_mrep); nd->nd_mrep = m = nd->nd_md; } else m = m->m_next; } if (m == NULL) { printf("nfsrv_readdsrpc: busted mbuf list\n"); error = ENOENT; goto nfsmout; } /* * Now, adjust first mbuf so that any XDR before the * read data is skipped over. */ trimlen = nd->nd_dpos - mtod(m, char *); if (trimlen > 0) { m->m_len -= trimlen; NFSM_DATAP(m, trimlen); } /* * Truncate the mbuf chain at retlen bytes of data, * plus XDR padding that brings the length up to a * multiple of 4. */ tlen = NFSM_RNDUP(retlen); do { if (m->m_len >= tlen) { m->m_len = tlen; tlen = 0; m2 = m->m_next; m->m_next = NULL; m_freem(m2); break; } tlen -= m->m_len; m = m->m_next; } while (m != NULL); if (tlen > 0) { printf("nfsrv_readdsrpc: busted mbuf list\n"); error = ENOENT; goto nfsmout; } *mpp = nd->nd_mrep; *mpendp = m; nd->nd_mrep = NULL; } } else error = nd->nd_repstat; nfsmout: /* If nd->nd_mrep is already NULL, this is a no-op. */ m_freem(nd->nd_mrep); free(nd, M_TEMP); NFSD_DEBUG(4, "nfsrv_readdsrpc error=%d\n", error); return (error); } /* * Do a write RPC on a DS data file, using this structure for the arguments, * so that this function can be executed by a separate kernel process. */ struct nfsrvwritedsdorpc { int done; int inprog; struct task tsk; fhandle_t fh; off_t off; int len; struct nfsmount *nmp; struct ucred *cred; NFSPROC_T *p; struct mbuf *m; int err; }; static int nfsrv_writedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, int len, struct nfsvattr *nap, struct mbuf *m, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript *nd; nfsattrbit_t attrbits; nfsv4stateid_t st; int commit, error, retlen; nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO); nfscl_reqstart(nd, NFSPROC_WRITE, nmp, (u_int8_t *)fhp, sizeof(fhandle_t), NULL, NULL, 0, 0, cred); /* * Use a stateid where other is an alternating 01010 pattern and * seqid is 0xffffffff. This value is not defined as special by * the RFC and is used by the FreeBSD NFS server to indicate an * MDS->DS proxy operation. */ st.other[0] = 0x55555555; st.other[1] = 0x55555555; st.other[2] = 0x55555555; st.seqid = 0xffffffff; nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); txdr_hyper(off, tl); tl += 2; /* * Do all writes FileSync, since the server doesn't hold onto dirty * buffers. Since clients should be accessing the DS servers directly * using the pNFS layouts, this just needs to work correctly as a * fallback. */ *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); *tl = txdr_unsigned(len); NFSD_DEBUG(4, "nfsrv_writedsdorpc: len=%d\n", len); /* Put data in mbuf chain. */ nd->nd_mb->m_next = m; /* Set nd_mb and nd_bpos to end of data. */ while (m->m_next != NULL) m = m->m_next; nd->nd_mb = m; nfsm_set(nd, m->m_len); NFSD_DEBUG(4, "nfsrv_writedsdorpc: lastmb len=%d\n", m->m_len); /* Do a Getattr for the attributes that change upon writing. */ NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESS); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SPACEUSED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) { free(nd, M_TEMP); return (error); } NFSD_DEBUG(4, "nfsrv_writedsdorpc: aft writerpc=%d\n", nd->nd_repstat); /* Get rid of weak cache consistency data for now. */ 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); NFSD_DEBUG(4, "nfsrv_writedsdorpc: wcc attr=%d\n", error); if (error != 0) goto nfsmout; /* * Get rid of Op# and status for next op. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*++tl != 0) nd->nd_flag |= ND_NOMOREDATA; } if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); retlen = fxdr_unsigned(int, *tl++); commit = fxdr_unsigned(int, *tl); if (commit != NFSWRITE_FILESYNC) error = NFSERR_IO; NFSD_DEBUG(4, "nfsrv_writedsdorpc:retlen=%d commit=%d err=%d\n", retlen, commit, error); } else error = nd->nd_repstat; /* We have no use for the Write Verifier since we use FileSync. */ /* * Get the Change, Size, Access Time and Modify Time attributes and set * on the Metadata file, so its attributes will be what the file's * would be if it had been written. */ 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); } NFSD_DEBUG(4, "nfsrv_writedsdorpc: aft loadattr=%d\n", error); nfsmout: m_freem(nd->nd_mrep); free(nd, M_TEMP); NFSD_DEBUG(4, "nfsrv_writedsdorpc error=%d\n", error); return (error); } /* * Start up the thread that will execute nfsrv_writedsdorpc(). */ static void start_writedsdorpc(void *arg, int pending) { struct nfsrvwritedsdorpc *drpc; drpc = (struct nfsrvwritedsdorpc *)arg; drpc->err = nfsrv_writedsdorpc(drpc->nmp, &drpc->fh, drpc->off, drpc->len, NULL, drpc->m, drpc->cred, drpc->p); drpc->done = 1; NFSD_DEBUG(4, "start_writedsdorpc: err=%d\n", drpc->err); } static int nfsrv_writedsrpc(fhandle_t *fhp, off_t off, int len, struct ucred *cred, NFSPROC_T *p, struct vnode *vp, struct nfsmount **nmpp, int mirrorcnt, struct mbuf **mpp, char *cp, int *failposp) { struct nfsrvwritedsdorpc *drpc, *tdrpc = NULL; struct nfsvattr na; struct mbuf *m; int error, i, offs, ret, timo; NFSD_DEBUG(4, "in nfsrv_writedsrpc\n"); KASSERT(*mpp != NULL, ("nfsrv_writedsrpc: NULL mbuf chain")); drpc = NULL; if (mirrorcnt > 1) tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP, M_WAITOK); /* Calculate offset in mbuf chain that data starts. */ offs = cp - mtod(*mpp, char *); NFSD_DEBUG(4, "nfsrv_writedsrpc: mcopy offs=%d len=%d\n", offs, len); /* * Do the write RPC for every DS, using a separate kernel process * for every DS except the last one. */ error = 0; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { tdrpc->done = 0; NFSBCOPY(fhp, &tdrpc->fh, sizeof(*fhp)); tdrpc->off = off; tdrpc->len = len; tdrpc->nmp = *nmpp; tdrpc->cred = cred; tdrpc->p = p; tdrpc->inprog = 0; tdrpc->err = 0; tdrpc->m = m_copym(*mpp, offs, NFSM_RNDUP(len), M_WAITOK); ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_writedsdorpc, tdrpc); NFSD_DEBUG(4, "nfsrv_writedsrpc: nfs_pnfsio=%d\n", ret); } if (ret != 0) { ret = nfsrv_writedsdorpc(*nmpp, fhp, off, len, NULL, tdrpc->m, cred, p); if (nfsds_failerr(ret) && *failposp == -1) *failposp = i; else if (error == 0 && ret != 0) error = ret; } nmpp++; fhp++; } m = m_copym(*mpp, offs, NFSM_RNDUP(len), M_WAITOK); ret = nfsrv_writedsdorpc(*nmpp, fhp, off, len, &na, m, cred, p); if (nfsds_failerr(ret) && *failposp == -1 && mirrorcnt > 1) *failposp = mirrorcnt - 1; else if (error == 0 && ret != 0) error = ret; if (error == 0) error = nfsrv_setextattr(vp, &na, p); NFSD_DEBUG(4, "nfsrv_writedsrpc: aft setextat=%d\n", error); tdrpc = drpc; timo = hz / 50; /* Wait for 20msec. */ if (timo < 1) timo = 1; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { /* Wait for RPCs on separate threads to complete. */ while (tdrpc->inprog != 0 && tdrpc->done == 0) tsleep(&tdrpc->tsk, PVFS, "srvwrds", timo); if (nfsds_failerr(tdrpc->err) && *failposp == -1) *failposp = i; else if (error == 0 && tdrpc->err != 0) error = tdrpc->err; } free(drpc, M_TEMP); return (error); } /* * Do a allocate RPC on a DS data file, using this structure for the arguments, * so that this function can be executed by a separate kernel process. */ struct nfsrvallocatedsdorpc { int done; int inprog; struct task tsk; fhandle_t fh; off_t off; off_t len; struct nfsmount *nmp; struct ucred *cred; NFSPROC_T *p; int err; }; static int nfsrv_allocatedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, off_t len, struct nfsvattr *nap, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript *nd; nfsattrbit_t attrbits; nfsv4stateid_t st; int error; nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO); nfscl_reqstart(nd, NFSPROC_ALLOCATE, nmp, (u_int8_t *)fhp, sizeof(fhandle_t), NULL, NULL, 0, 0, cred); /* * Use a stateid where other is an alternating 01010 pattern and * seqid is 0xffffffff. This value is not defined as special by * the RFC and is used by the FreeBSD NFS server to indicate an * MDS->DS proxy operation. */ st.other[0] = 0x55555555; st.other[1] = 0x55555555; st.other[2] = 0x55555555; st.seqid = 0xffffffff; nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); txdr_hyper(off, tl); tl += 2; txdr_hyper(len, tl); tl += 2; NFSD_DEBUG(4, "nfsrv_allocatedsdorpc: len=%jd\n", (intmax_t)len); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSGETATTR_ATTRBIT(&attrbits); nfsrv_putattrbit(nd, &attrbits); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) { free(nd, M_TEMP); return (error); } NFSD_DEBUG(4, "nfsrv_allocatedsdorpc: aft allocaterpc=%d\n", nd->nd_repstat); 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); } else error = nd->nd_repstat; NFSD_DEBUG(4, "nfsrv_allocatedsdorpc: aft loadattr=%d\n", error); nfsmout: m_freem(nd->nd_mrep); free(nd, M_TEMP); NFSD_DEBUG(4, "nfsrv_allocatedsdorpc error=%d\n", error); return (error); } /* * Start up the thread that will execute nfsrv_allocatedsdorpc(). */ static void start_allocatedsdorpc(void *arg, int pending) { struct nfsrvallocatedsdorpc *drpc; drpc = (struct nfsrvallocatedsdorpc *)arg; drpc->err = nfsrv_allocatedsdorpc(drpc->nmp, &drpc->fh, drpc->off, drpc->len, NULL, drpc->cred, drpc->p); drpc->done = 1; NFSD_DEBUG(4, "start_allocatedsdorpc: err=%d\n", drpc->err); } static int nfsrv_allocatedsrpc(fhandle_t *fhp, off_t off, off_t len, struct ucred *cred, NFSPROC_T *p, struct vnode *vp, struct nfsmount **nmpp, int mirrorcnt, int *failposp) { struct nfsrvallocatedsdorpc *drpc, *tdrpc = NULL; struct nfsvattr na; int error, i, ret, timo; NFSD_DEBUG(4, "in nfsrv_allocatedsrpc\n"); drpc = NULL; if (mirrorcnt > 1) tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP, M_WAITOK); /* * Do the allocate RPC for every DS, using a separate kernel process * for every DS except the last one. */ error = 0; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { tdrpc->done = 0; NFSBCOPY(fhp, &tdrpc->fh, sizeof(*fhp)); tdrpc->off = off; tdrpc->len = len; tdrpc->nmp = *nmpp; tdrpc->cred = cred; tdrpc->p = p; tdrpc->inprog = 0; tdrpc->err = 0; ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_allocatedsdorpc, tdrpc); NFSD_DEBUG(4, "nfsrv_allocatedsrpc: nfs_pnfsio=%d\n", ret); } if (ret != 0) { ret = nfsrv_allocatedsdorpc(*nmpp, fhp, off, len, NULL, cred, p); if (nfsds_failerr(ret) && *failposp == -1) *failposp = i; else if (error == 0 && ret != 0) error = ret; } nmpp++; fhp++; } ret = nfsrv_allocatedsdorpc(*nmpp, fhp, off, len, &na, cred, p); if (nfsds_failerr(ret) && *failposp == -1 && mirrorcnt > 1) *failposp = mirrorcnt - 1; else if (error == 0 && ret != 0) error = ret; if (error == 0) error = nfsrv_setextattr(vp, &na, p); NFSD_DEBUG(4, "nfsrv_allocatedsrpc: aft setextat=%d\n", error); tdrpc = drpc; timo = hz / 50; /* Wait for 20msec. */ if (timo < 1) timo = 1; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { /* Wait for RPCs on separate threads to complete. */ while (tdrpc->inprog != 0 && tdrpc->done == 0) tsleep(&tdrpc->tsk, PVFS, "srvalds", timo); if (nfsds_failerr(tdrpc->err) && *failposp == -1) *failposp = i; else if (error == 0 && tdrpc->err != 0) error = tdrpc->err; } free(drpc, M_TEMP); return (error); } /* * Do a deallocate RPC on a DS data file, using this structure for the * arguments, so that this function can be executed by a separate kernel * process. */ struct nfsrvdeallocatedsdorpc { int done; int inprog; struct task tsk; fhandle_t fh; off_t off; off_t len; struct nfsmount *nmp; struct ucred *cred; NFSPROC_T *p; int err; }; static int nfsrv_deallocatedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, off_t len, struct nfsvattr *nap, struct ucred *cred, NFSPROC_T *p) { uint32_t *tl; struct nfsrv_descript *nd; nfsattrbit_t attrbits; nfsv4stateid_t st; int error; nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO); nfscl_reqstart(nd, NFSPROC_DEALLOCATE, nmp, (u_int8_t *)fhp, sizeof(fhandle_t), NULL, NULL, 0, 0, cred); /* * Use a stateid where other is an alternating 01010 pattern and * seqid is 0xffffffff. This value is not defined as special by * the RFC and is used by the FreeBSD NFS server to indicate an * MDS->DS proxy operation. */ st.other[0] = 0x55555555; st.other[1] = 0x55555555; st.other[2] = 0x55555555; st.seqid = 0xffffffff; nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); txdr_hyper(off, tl); tl += 2; txdr_hyper(len, tl); tl += 2; NFSD_DEBUG(4, "nfsrv_deallocatedsdorpc: len=%jd\n", (intmax_t)len); /* Do a Getattr for the attributes that change upon writing. */ NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESS); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SPACEUSED); *tl = txdr_unsigned(NFSV4OP_GETATTR); nfsrv_putattrbit(nd, &attrbits); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) { free(nd, M_TEMP); return (error); } NFSD_DEBUG(4, "nfsrv_deallocatedsdorpc: aft deallocaterpc=%d\n", nd->nd_repstat); /* Get rid of weak cache consistency data for now. */ 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); NFSD_DEBUG(4, "nfsrv_deallocatedsdorpc: wcc attr=%d\n", error); if (error != 0) goto nfsmout; /* * Get rid of Op# and status for next op. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*++tl != 0) nd->nd_flag |= ND_NOMOREDATA; } 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); } else error = nd->nd_repstat; NFSD_DEBUG(4, "nfsrv_deallocatedsdorpc: aft loadattr=%d\n", error); nfsmout: m_freem(nd->nd_mrep); free(nd, M_TEMP); NFSD_DEBUG(4, "nfsrv_deallocatedsdorpc error=%d\n", error); return (error); } /* * Start up the thread that will execute nfsrv_deallocatedsdorpc(). */ static void start_deallocatedsdorpc(void *arg, int pending) { struct nfsrvdeallocatedsdorpc *drpc; drpc = (struct nfsrvdeallocatedsdorpc *)arg; drpc->err = nfsrv_deallocatedsdorpc(drpc->nmp, &drpc->fh, drpc->off, drpc->len, NULL, drpc->cred, drpc->p); drpc->done = 1; NFSD_DEBUG(4, "start_deallocatedsdorpc: err=%d\n", drpc->err); } static int nfsrv_deallocatedsrpc(fhandle_t *fhp, off_t off, off_t len, struct ucred *cred, NFSPROC_T *p, struct vnode *vp, struct nfsmount **nmpp, int mirrorcnt, int *failposp) { struct nfsrvdeallocatedsdorpc *drpc, *tdrpc = NULL; struct nfsvattr na; int error, i, ret, timo; NFSD_DEBUG(4, "in nfsrv_deallocatedsrpc\n"); drpc = NULL; if (mirrorcnt > 1) tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP, M_WAITOK); /* * Do the deallocate RPC for every DS, using a separate kernel process * for every DS except the last one. */ error = 0; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { tdrpc->done = 0; NFSBCOPY(fhp, &tdrpc->fh, sizeof(*fhp)); tdrpc->off = off; tdrpc->len = len; tdrpc->nmp = *nmpp; tdrpc->cred = cred; tdrpc->p = p; tdrpc->inprog = 0; tdrpc->err = 0; ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_deallocatedsdorpc, tdrpc); NFSD_DEBUG(4, "nfsrv_deallocatedsrpc: nfs_pnfsio=%d\n", ret); } if (ret != 0) { ret = nfsrv_deallocatedsdorpc(*nmpp, fhp, off, len, NULL, cred, p); if (nfsds_failerr(ret) && *failposp == -1) *failposp = i; else if (error == 0 && ret != 0) error = ret; } nmpp++; fhp++; } ret = nfsrv_deallocatedsdorpc(*nmpp, fhp, off, len, &na, cred, p); if (nfsds_failerr(ret) && *failposp == -1 && mirrorcnt > 1) *failposp = mirrorcnt - 1; else if (error == 0 && ret != 0) error = ret; if (error == 0) error = nfsrv_setextattr(vp, &na, p); NFSD_DEBUG(4, "nfsrv_deallocatedsrpc: aft setextat=%d\n", error); tdrpc = drpc; timo = hz / 50; /* Wait for 20msec. */ if (timo < 1) timo = 1; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { /* Wait for RPCs on separate threads to complete. */ while (tdrpc->inprog != 0 && tdrpc->done == 0) tsleep(&tdrpc->tsk, PVFS, "srvalds", timo); if (nfsds_failerr(tdrpc->err) && *failposp == -1) *failposp = i; else if (error == 0 && tdrpc->err != 0) error = tdrpc->err; } free(drpc, M_TEMP); return (error); } static int nfsrv_setattrdsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p, struct vnode *vp, struct nfsmount *nmp, struct nfsvattr *nap, struct nfsvattr *dsnap) { uint32_t *tl; struct nfsrv_descript *nd; nfsv4stateid_t st; nfsattrbit_t attrbits; int error; NFSD_DEBUG(4, "in nfsrv_setattrdsdorpc\n"); nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO); /* * Use a stateid where other is an alternating 01010 pattern and * seqid is 0xffffffff. This value is not defined as special by * the RFC and is used by the FreeBSD NFS server to indicate an * MDS->DS proxy operation. */ st.other[0] = 0x55555555; st.other[1] = 0x55555555; st.other[2] = 0x55555555; st.seqid = 0xffffffff; nfscl_reqstart(nd, NFSPROC_SETATTR, nmp, (u_int8_t *)fhp, sizeof(*fhp), NULL, NULL, 0, 0, cred); nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID); nfscl_fillsattr(nd, &nap->na_vattr, vp, NFSSATTR_FULL, 0); /* Do a Getattr for the attributes that change due to writing. */ NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESS); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SPACEUSED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) { free(nd, M_TEMP); return (error); } NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: aft setattrrpc=%d\n", nd->nd_repstat); /* Get rid of weak cache consistency data for now. */ 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); NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: wcc attr=%d\n", error); if (error != 0) goto nfsmout; /* * Get rid of Op# and status for next op. */ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*++tl != 0) nd->nd_flag |= ND_NOMOREDATA; } error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error != 0) goto nfsmout; if (nd->nd_repstat != 0) error = nd->nd_repstat; /* * Get the Change, Size, Access Time and Modify Time attributes and set * on the Metadata file, so its attributes will be what the file's * would be if it had been written. */ if (error == 0) { 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); } NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: aft setattr loadattr=%d\n", error); nfsmout: m_freem(nd->nd_mrep); free(nd, M_TEMP); NFSD_DEBUG(4, "nfsrv_setattrdsdorpc error=%d\n", error); return (error); } struct nfsrvsetattrdsdorpc { int done; int inprog; struct task tsk; fhandle_t fh; struct nfsmount *nmp; struct vnode *vp; struct ucred *cred; NFSPROC_T *p; struct nfsvattr na; struct nfsvattr dsna; int err; }; /* * Start up the thread that will execute nfsrv_setattrdsdorpc(). */ static void start_setattrdsdorpc(void *arg, int pending) { struct nfsrvsetattrdsdorpc *drpc; drpc = (struct nfsrvsetattrdsdorpc *)arg; drpc->err = nfsrv_setattrdsdorpc(&drpc->fh, drpc->cred, drpc->p, drpc->vp, drpc->nmp, &drpc->na, &drpc->dsna); drpc->done = 1; } static int nfsrv_setattrdsrpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p, struct vnode *vp, struct nfsmount **nmpp, int mirrorcnt, struct nfsvattr *nap, int *failposp) { struct nfsrvsetattrdsdorpc *drpc, *tdrpc = NULL; struct nfsvattr na; int error, i, ret, timo; NFSD_DEBUG(4, "in nfsrv_setattrdsrpc\n"); drpc = NULL; if (mirrorcnt > 1) tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP, M_WAITOK); /* * Do the setattr RPC for every DS, using a separate kernel process * for every DS except the last one. */ error = 0; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { tdrpc->done = 0; tdrpc->inprog = 0; NFSBCOPY(fhp, &tdrpc->fh, sizeof(*fhp)); tdrpc->nmp = *nmpp; tdrpc->vp = vp; tdrpc->cred = cred; tdrpc->p = p; tdrpc->na = *nap; tdrpc->err = 0; ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_setattrdsdorpc, tdrpc); NFSD_DEBUG(4, "nfsrv_setattrdsrpc: nfs_pnfsio=%d\n", ret); } if (ret != 0) { ret = nfsrv_setattrdsdorpc(fhp, cred, p, vp, *nmpp, nap, &na); if (nfsds_failerr(ret) && *failposp == -1) *failposp = i; else if (error == 0 && ret != 0) error = ret; } nmpp++; fhp++; } ret = nfsrv_setattrdsdorpc(fhp, cred, p, vp, *nmpp, nap, &na); if (nfsds_failerr(ret) && *failposp == -1 && mirrorcnt > 1) *failposp = mirrorcnt - 1; else if (error == 0 && ret != 0) error = ret; if (error == 0) error = nfsrv_setextattr(vp, &na, p); NFSD_DEBUG(4, "nfsrv_setattrdsrpc: aft setextat=%d\n", error); tdrpc = drpc; timo = hz / 50; /* Wait for 20msec. */ if (timo < 1) timo = 1; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { /* Wait for RPCs on separate threads to complete. */ while (tdrpc->inprog != 0 && tdrpc->done == 0) tsleep(&tdrpc->tsk, PVFS, "srvsads", timo); if (nfsds_failerr(tdrpc->err) && *failposp == -1) *failposp = i; else if (error == 0 && tdrpc->err != 0) error = tdrpc->err; } free(drpc, M_TEMP); return (error); } /* * Do a Setattr of an NFSv4 ACL on the DS file. */ static int nfsrv_setacldsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p, struct vnode *vp, struct nfsmount *nmp, struct acl *aclp) { struct nfsrv_descript *nd; nfsv4stateid_t st; nfsattrbit_t attrbits; int error; NFSD_DEBUG(4, "in nfsrv_setacldsdorpc\n"); nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO); /* * Use a stateid where other is an alternating 01010 pattern and * seqid is 0xffffffff. This value is not defined as special by * the RFC and is used by the FreeBSD NFS server to indicate an * MDS->DS proxy operation. */ st.other[0] = 0x55555555; st.other[1] = 0x55555555; st.other[2] = 0x55555555; st.seqid = 0xffffffff; nfscl_reqstart(nd, NFSPROC_SETACL, nmp, (u_int8_t *)fhp, sizeof(*fhp), NULL, NULL, 0, 0, cred); nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID); NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); /* * The "vp" argument to nfsv4_fillattr() is only used for vnode_type(), * so passing in the metadata "vp" will be ok, since it is of * 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, 0); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) { free(nd, M_TEMP); return (error); } NFSD_DEBUG(4, "nfsrv_setacldsdorpc: aft setaclrpc=%d\n", nd->nd_repstat); error = nd->nd_repstat; m_freem(nd->nd_mrep); free(nd, M_TEMP); return (error); } struct nfsrvsetacldsdorpc { int done; int inprog; struct task tsk; fhandle_t fh; struct nfsmount *nmp; struct vnode *vp; struct ucred *cred; NFSPROC_T *p; struct acl *aclp; int err; }; /* * Start up the thread that will execute nfsrv_setacldsdorpc(). */ static void start_setacldsdorpc(void *arg, int pending) { struct nfsrvsetacldsdorpc *drpc; drpc = (struct nfsrvsetacldsdorpc *)arg; drpc->err = nfsrv_setacldsdorpc(&drpc->fh, drpc->cred, drpc->p, drpc->vp, drpc->nmp, drpc->aclp); drpc->done = 1; } static int nfsrv_setacldsrpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p, struct vnode *vp, struct nfsmount **nmpp, int mirrorcnt, struct acl *aclp, int *failposp) { struct nfsrvsetacldsdorpc *drpc, *tdrpc = NULL; int error, i, ret, timo; NFSD_DEBUG(4, "in nfsrv_setacldsrpc\n"); drpc = NULL; if (mirrorcnt > 1) tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP, M_WAITOK); /* * Do the setattr RPC for every DS, using a separate kernel process * for every DS except the last one. */ error = 0; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { tdrpc->done = 0; tdrpc->inprog = 0; NFSBCOPY(fhp, &tdrpc->fh, sizeof(*fhp)); tdrpc->nmp = *nmpp; tdrpc->vp = vp; tdrpc->cred = cred; tdrpc->p = p; tdrpc->aclp = aclp; tdrpc->err = 0; ret = EIO; if (nfs_pnfsiothreads != 0) { ret = nfs_pnfsio(start_setacldsdorpc, tdrpc); NFSD_DEBUG(4, "nfsrv_setacldsrpc: nfs_pnfsio=%d\n", ret); } if (ret != 0) { ret = nfsrv_setacldsdorpc(fhp, cred, p, vp, *nmpp, aclp); if (nfsds_failerr(ret) && *failposp == -1) *failposp = i; else if (error == 0 && ret != 0) error = ret; } nmpp++; fhp++; } ret = nfsrv_setacldsdorpc(fhp, cred, p, vp, *nmpp, aclp); if (nfsds_failerr(ret) && *failposp == -1 && mirrorcnt > 1) *failposp = mirrorcnt - 1; else if (error == 0 && ret != 0) error = ret; NFSD_DEBUG(4, "nfsrv_setacldsrpc: aft setextat=%d\n", error); tdrpc = drpc; timo = hz / 50; /* Wait for 20msec. */ if (timo < 1) timo = 1; for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) { /* Wait for RPCs on separate threads to complete. */ while (tdrpc->inprog != 0 && tdrpc->done == 0) tsleep(&tdrpc->tsk, PVFS, "srvacds", timo); if (nfsds_failerr(tdrpc->err) && *failposp == -1) *failposp = i; else if (error == 0 && tdrpc->err != 0) error = tdrpc->err; } free(drpc, M_TEMP); return (error); } /* * Getattr call to the DS for the attributes that change due to writing. */ static int nfsrv_getattrdsrpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p, struct vnode *vp, struct nfsmount *nmp, struct nfsvattr *nap) { struct nfsrv_descript *nd; int error; nfsattrbit_t attrbits; NFSD_DEBUG(4, "in nfsrv_getattrdsrpc\n"); nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO); nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, (u_int8_t *)fhp, sizeof(fhandle_t), NULL, NULL, 0, 0, cred); NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESS); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SPACEUSED); (void) nfsrv_putattrbit(nd, &attrbits); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) { free(nd, M_TEMP); return (error); } NFSD_DEBUG(4, "nfsrv_getattrdsrpc: aft getattrrpc=%d\n", nd->nd_repstat); 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); /* * We can only save the updated values in the extended * attribute if the vp is exclusively locked. * This should happen when any of the following operations * occur on the vnode: * Close, Delegreturn, LayoutCommit, LayoutReturn * As such, the updated extended attribute should get saved * before nfsrv_checkdsattr() returns 0 and allows the cached * attributes to be returned without calling this function. */ if (error == 0 && VOP_ISLOCKED(vp) == LK_EXCLUSIVE) { error = nfsrv_setextattr(vp, nap, p); NFSD_DEBUG(4, "nfsrv_getattrdsrpc: aft setextat=%d\n", error); } } else error = nd->nd_repstat; m_freem(nd->nd_mrep); free(nd, M_TEMP); NFSD_DEBUG(4, "nfsrv_getattrdsrpc error=%d\n", error); return (error); } /* * Seek call to a DS. */ static int nfsrv_seekdsrpc(fhandle_t *fhp, off_t *offp, int content, bool *eofp, struct ucred *cred, NFSPROC_T *p, struct nfsmount *nmp) { uint32_t *tl; struct nfsrv_descript *nd; nfsv4stateid_t st; int error; NFSD_DEBUG(4, "in nfsrv_seekdsrpc\n"); /* * Use a stateid where other is an alternating 01010 pattern and * seqid is 0xffffffff. This value is not defined as special by * the RFC and is used by the FreeBSD NFS server to indicate an * MDS->DS proxy operation. */ st.other[0] = 0x55555555; st.other[1] = 0x55555555; st.other[2] = 0x55555555; st.seqid = 0xffffffff; nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO); nfscl_reqstart(nd, NFSPROC_SEEKDS, nmp, (u_int8_t *)fhp, sizeof(fhandle_t), NULL, NULL, 0, 0, cred); nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); txdr_hyper(*offp, tl); tl += 2; *tl = txdr_unsigned(content); error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) { free(nd, M_TEMP); return (error); } NFSD_DEBUG(4, "nfsrv_seekdsrpc: aft seekrpc=%d\n", nd->nd_repstat); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); if (*tl++ == newnfs_true) *eofp = true; else *eofp = false; *offp = fxdr_hyper(tl); } else error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); free(nd, M_TEMP); NFSD_DEBUG(4, "nfsrv_seekdsrpc error=%d\n", error); return (error); } /* * Get the device id and file handle for a DS file. */ int nfsrv_dsgetdevandfh(struct vnode *vp, NFSPROC_T *p, int *mirrorcntp, fhandle_t *fhp, char *devid) { int buflen, error; char *buf; buflen = 1024; buf = malloc(buflen, M_TEMP, M_WAITOK); error = nfsrv_dsgetsockmnt(vp, 0, buf, &buflen, mirrorcntp, p, NULL, fhp, devid, NULL, NULL, NULL, NULL, NULL, NULL); free(buf, M_TEMP); return (error); } /* * Do a Lookup against the DS for the filename. */ static int nfsrv_pnfslookupds(struct vnode *vp, struct vnode *dvp, struct pnfsdsfile *pf, struct vnode **nvpp, NFSPROC_T *p) { struct nameidata named; struct ucred *tcred; char *bufp; u_long *hashp; struct vnode *nvp; int error; tcred = newnfs_getcred(); named.ni_cnd.cn_nameiop = LOOKUP; named.ni_cnd.cn_lkflags = LK_SHARED | LK_RETRY; named.ni_cnd.cn_cred = tcred; named.ni_cnd.cn_flags = ISLASTCN | LOCKPARENT | LOCKLEAF; nfsvno_setpathbuf(&named, &bufp, &hashp); named.ni_cnd.cn_nameptr = bufp; named.ni_cnd.cn_namelen = strlen(pf->dsf_filename); strlcpy(bufp, pf->dsf_filename, NAME_MAX); NFSD_DEBUG(4, "nfsrv_pnfslookupds: filename=%s\n", bufp); error = VOP_LOOKUP(dvp, &nvp, &named.ni_cnd); NFSD_DEBUG(4, "nfsrv_pnfslookupds: aft LOOKUP=%d\n", error); NFSFREECRED(tcred); nfsvno_relpathbuf(&named); if (error == 0) *nvpp = nvp; NFSD_DEBUG(4, "eo nfsrv_pnfslookupds=%d\n", error); return (error); } /* * Set the file handle to the correct one. */ static void nfsrv_pnfssetfh(struct vnode *vp, struct pnfsdsfile *pf, char *devid, char *fnamep, struct vnode *nvp, NFSPROC_T *p) { struct nfsnode *np; int ret = 0; np = VTONFS(nvp); NFSBCOPY(np->n_fhp->nfh_fh, &pf->dsf_fh, NFSX_MYFH); /* * We can only do a vn_set_extattr() if the vnode is exclusively * locked and vn_start_write() has been done. If devid != NULL or * fnamep != NULL or the vnode is shared locked, vn_start_write() * may not have been done. * If not done now, it will be done on a future call. */ if (devid == NULL && fnamep == NULL && NFSVOPISLOCKED(vp) == LK_EXCLUSIVE) ret = vn_extattr_set(vp, IO_NODELOCKED, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile", sizeof(*pf), (char *)pf, p); NFSD_DEBUG(4, "eo nfsrv_pnfssetfh=%d\n", ret); } /* * Cause RPCs waiting on "nmp" to fail. This is called for a DS mount point * when the DS has failed. */ void nfsrv_killrpcs(struct nfsmount *nmp) { /* * Call newnfs_nmcancelreqs() to cause * any RPCs in progress on the mount point to * fail. * This will cause any process waiting for an * RPC to complete while holding a vnode lock * on the mounted-on vnode (such as "df" or * a non-forced "umount") to fail. * This will unlock the mounted-on vnode so * a forced dismount can succeed. * The NFSMNTP_CANCELRPCS flag should be set when this function is * called. */ newnfs_nmcancelreqs(nmp); } /* * Sum up the statfs info for each of the DSs, so that the client will * receive the total for all DSs. */ static int nfsrv_pnfsstatfs(struct statfs *sf, struct mount *mp) { struct statfs *tsf; struct nfsdevice *ds; struct vnode **dvpp, **tdvpp, *dvp; uint64_t tot; int cnt, error = 0, i; if (nfsrv_devidcnt <= 0) return (ENXIO); dvpp = mallocarray(nfsrv_devidcnt, sizeof(*dvpp), M_TEMP, M_WAITOK); tsf = malloc(sizeof(*tsf), M_TEMP, M_WAITOK); /* Get an array of the dvps for the DSs. */ tdvpp = dvpp; i = 0; NFSDDSLOCK(); /* First, search for matches for same file system. */ TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) { if (ds->nfsdev_nmp != NULL && ds->nfsdev_mdsisset != 0 && fsidcmp(&ds->nfsdev_mdsfsid, &mp->mnt_stat.f_fsid) == 0) { if (++i > nfsrv_devidcnt) break; *tdvpp++ = ds->nfsdev_dvp; } } /* * If no matches for same file system, total all servers not assigned * to a file system. */ if (i == 0) { TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) { if (ds->nfsdev_nmp != NULL && ds->nfsdev_mdsisset == 0) { if (++i > nfsrv_devidcnt) break; *tdvpp++ = ds->nfsdev_dvp; } } } NFSDDSUNLOCK(); cnt = i; /* Do a VFS_STATFS() for each of the DSs and sum them up. */ tdvpp = dvpp; for (i = 0; i < cnt && error == 0; i++) { dvp = *tdvpp++; error = VFS_STATFS(dvp->v_mount, tsf); if (error == 0) { if (sf->f_bsize == 0) { if (tsf->f_bsize > 0) sf->f_bsize = tsf->f_bsize; else sf->f_bsize = 8192; } if (tsf->f_blocks > 0) { if (sf->f_bsize != tsf->f_bsize) { tot = tsf->f_blocks * tsf->f_bsize; sf->f_blocks += (tot / sf->f_bsize); } else sf->f_blocks += tsf->f_blocks; } if (tsf->f_bfree > 0) { if (sf->f_bsize != tsf->f_bsize) { tot = tsf->f_bfree * tsf->f_bsize; sf->f_bfree += (tot / sf->f_bsize); } else sf->f_bfree += tsf->f_bfree; } if (tsf->f_bavail > 0) { if (sf->f_bsize != tsf->f_bsize) { tot = tsf->f_bavail * tsf->f_bsize; sf->f_bavail += (tot / sf->f_bsize); } else sf->f_bavail += tsf->f_bavail; } } } free(tsf, M_TEMP); free(dvpp, M_TEMP); return (error); } /* * Set an NFSv4 acl. */ int nfsrv_setacl(struct vnode *vp, NFSACL_T *aclp, struct ucred *cred, NFSPROC_T *p) { int error; if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) { error = NFSERR_ATTRNOTSUPP; goto out; } /* * With NFSv4 ACLs, chmod(2) may need to add additional entries. * Make sure it has enough room for that - splitting every entry * into two and appending "canonical six" entries at the end. * Cribbed out of kern/vfs_acl.c - Rick M. */ if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) { error = NFSERR_ATTRNOTSUPP; goto out; } error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p); if (error == 0) { error = nfsrv_dssetacl(vp, aclp, cred, p); if (error == ENOENT) error = 0; } out: NFSEXITCODE(error); return (error); } /* * Seek vnode op call (actually it is a VOP_IOCTL()). * This function is called with the vnode locked, but unlocks and vrele()s * the vp before returning. */ int nfsvno_seek(struct nfsrv_descript *nd, struct vnode *vp, u_long cmd, off_t *offp, int content, bool *eofp, struct ucred *cred, NFSPROC_T *p) { struct nfsvattr at; int error, ret; ASSERT_VOP_LOCKED(vp, "nfsvno_seek vp"); /* * Attempt to seek on a DS file. A return of ENOENT implies * there is no DS file to seek on. */ error = nfsrv_proxyds(vp, 0, 0, cred, p, NFSPROC_SEEKDS, NULL, NULL, NULL, NULL, NULL, offp, content, eofp); if (error != ENOENT) { vput(vp); return (error); } /* * Do the VOP_IOCTL() call. For the case where *offp == file_size, * VOP_IOCTL() will return ENXIO. However, the correct reply for * NFSv4.2 is *eofp == true and error == 0 for this case. */ NFSVOPUNLOCK(vp); error = VOP_IOCTL(vp, cmd, offp, 0, cred, p); *eofp = false; if (error == ENXIO || (error == 0 && cmd == FIOSEEKHOLE)) { /* Handle the cases where we might be at EOF. */ ret = nfsvno_getattr(vp, &at, nd, p, 0, NULL); if (ret == 0 && *offp == at.na_size) { *eofp = true; error = 0; } if (ret != 0 && error == 0) error = ret; } vrele(vp); NFSEXITCODE(error); return (error); } /* * Allocate vnode op call. */ int nfsvno_allocate(struct vnode *vp, off_t off, off_t len, struct ucred *cred, NFSPROC_T *p) { int error; off_t olen; ASSERT_VOP_ELOCKED(vp, "nfsvno_allocate vp"); /* * Attempt to allocate on a DS file. A return of ENOENT implies * there is no DS file to allocate on. */ error = nfsrv_proxyds(vp, off, 0, cred, p, NFSPROC_ALLOCATE, NULL, NULL, NULL, NULL, NULL, &len, 0, NULL); if (error != ENOENT) return (error); /* * Do the actual VOP_ALLOCATE(), looping so long as * progress is being made, to achieve completion. */ do { olen = len; error = VOP_ALLOCATE(vp, &off, &len, IO_SYNC, cred); if (error == 0 && len > 0 && olen > len) maybe_yield(); } while (error == 0 && len > 0 && olen > len); if (error == 0 && len > 0) error = NFSERR_IO; NFSEXITCODE(error); return (error); } /* * Deallocate vnode op call. */ int nfsvno_deallocate(struct vnode *vp, off_t off, off_t len, struct ucred *cred, NFSPROC_T *p) { int error; off_t olen; ASSERT_VOP_ELOCKED(vp, "nfsvno_deallocate vp"); /* * Attempt to deallocate on a DS file. A return of ENOENT implies * there is no DS file to deallocate on. */ error = nfsrv_proxyds(vp, off, 0, cred, p, NFSPROC_DEALLOCATE, NULL, NULL, NULL, NULL, NULL, &len, 0, NULL); if (error != ENOENT) return (error); /* * Do the actual VOP_DEALLOCATE(), looping so long as * progress is being made, to achieve completion. */ do { olen = len; error = VOP_DEALLOCATE(vp, &off, &len, 0, IO_SYNC, cred); if (error == 0 && len > 0 && olen > len) maybe_yield(); } while (error == 0 && len > 0 && olen > len); if (error == 0 && len > 0) error = NFSERR_IO; NFSEXITCODE(error); return (error); } /* * Get Extended Atribute vnode op into an mbuf list. */ int nfsvno_getxattr(struct vnode *vp, char *name, uint32_t maxresp, struct ucred *cred, uint64_t flag, int maxextsiz, struct thread *p, struct mbuf **mpp, struct mbuf **mpendp, int *lenp) { struct iovec *iv; struct uio io, *uiop = &io; struct mbuf *m, *m2; int alen, error, len, tlen; size_t siz; /* First, find out the size of the extended attribute. */ error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, &siz, cred, p); if (error != 0) return (NFSERR_NOXATTR); if (siz > maxresp - NFS_MAXXDR) return (NFSERR_XATTR2BIG); len = siz; tlen = NFSM_RNDUP(len); if (tlen > 0) { /* * If cnt > MCLBYTES and the reply will not be saved, use * ext_pgs mbufs for TLS. * For NFSv4.0, we do not know for sure if the reply will * be saved, so do not use ext_pgs mbufs for NFSv4.0. * Always use ext_pgs mbufs if ND_EXTPG is set. */ if ((flag & ND_EXTPG) != 0 || (tlen > MCLBYTES && (flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS && (flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4)) uiop->uio_iovcnt = nfsrv_createiovec_extpgs(tlen, maxextsiz, &m, &m2, &iv); else uiop->uio_iovcnt = nfsrv_createiovec(tlen, &m, &m2, &iv); uiop->uio_iov = iv; } else { uiop->uio_iovcnt = 0; uiop->uio_iov = iv = NULL; m = m2 = NULL; } uiop->uio_offset = 0; uiop->uio_resid = tlen; uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_td = p; #ifdef MAC error = mac_vnode_check_getextattr(cred, vp, EXTATTR_NAMESPACE_USER, name); if (error != 0) goto out; #endif if (tlen > 0) error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, uiop, NULL, cred, p); if (error != 0) goto out; if (uiop->uio_resid > 0) { alen = tlen; len = tlen - uiop->uio_resid; tlen = NFSM_RNDUP(len); if (alen != tlen) printf("nfsvno_getxattr: weird size read\n"); if (tlen == 0) { m_freem(m); m = m2 = NULL; } else if (alen != tlen || tlen != len) m2 = nfsrv_adj(m, alen - tlen, tlen - len); } *lenp = len; *mpp = m; *mpendp = m2; out: if (error != 0) { if (m != NULL) m_freem(m); *lenp = 0; } free(iv, M_TEMP); NFSEXITCODE(error); return (error); } /* * Set Extended attribute vnode op from an mbuf list. */ int nfsvno_setxattr(struct vnode *vp, char *name, int len, struct mbuf *m, char *cp, struct ucred *cred, struct thread *p) { struct iovec *iv; struct uio uio, *uiop = &uio; int cnt, error; error = 0; #ifdef MAC error = mac_vnode_check_setextattr(cred, vp, EXTATTR_NAMESPACE_USER, name); #endif if (error != 0) goto out; uiop->uio_rw = UIO_WRITE; uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_td = p; uiop->uio_offset = 0; uiop->uio_resid = len; if (len > 0) { error = nfsrv_createiovecw(len, m, cp, &iv, &cnt); uiop->uio_iov = iv; uiop->uio_iovcnt = cnt; } else { uiop->uio_iov = iv = NULL; uiop->uio_iovcnt = 0; } if (error == 0) { error = VOP_SETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, uiop, cred, p); if (error == 0) { if (vp->v_type == VREG && nfsrv_devidcnt != 0) nfsvno_updateds(vp, cred, p); error = VOP_FSYNC(vp, MNT_WAIT, p); } free(iv, M_TEMP); } out: NFSEXITCODE(error); return (error); } /* * For a pNFS server, the DS file's ctime and * va_filerev (TimeMetadata and Change) needs to * be updated. This is a hack, but works by * flipping the S_ISGID bit in va_mode and then * flipping it back. * It does result in two MDS->DS RPCs, but creating * a custom RPC just to do this seems overkill, since * Setxattr/Rmxattr will not be done that frequently. * If it fails part way through, that is not too * serious, since the DS file is never executed. */ static void nfsvno_updateds(struct vnode *vp, struct ucred *cred, NFSPROC_T *p) { struct nfsvattr nva; int ret; u_short tmode; ret = VOP_GETATTR(vp, &nva.na_vattr, cred); if (ret == 0) { tmode = nva.na_mode; NFSVNO_ATTRINIT(&nva); tmode ^= S_ISGID; NFSVNO_SETATTRVAL(&nva, mode, tmode); ret = nfsrv_proxyds(vp, 0, 0, cred, p, NFSPROC_SETATTR, NULL, NULL, NULL, &nva, NULL, NULL, 0, NULL); if (ret == 0) { tmode ^= S_ISGID; NFSVNO_SETATTRVAL(&nva, mode, tmode); ret = nfsrv_proxyds(vp, 0, 0, cred, p, NFSPROC_SETATTR, NULL, NULL, NULL, &nva, NULL, NULL, 0, NULL); } } } /* * Remove Extended attribute vnode op. */ int nfsvno_rmxattr(struct nfsrv_descript *nd, struct vnode *vp, char *name, struct ucred *cred, struct thread *p) { int error; /* * Get rid of any delegations. I am not sure why this is required, * but RFC-8276 says so. */ error = nfsrv_checkremove(vp, 0, nd, nd->nd_clientid, p); if (error != 0) goto out; #ifdef MAC error = mac_vnode_check_deleteextattr(cred, vp, EXTATTR_NAMESPACE_USER, name); if (error != 0) goto out; #endif error = VOP_DELETEEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, cred, p); if (error == EOPNOTSUPP) error = VOP_SETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, cred, p); if (error == 0) { if (vp->v_type == VREG && nfsrv_devidcnt != 0) nfsvno_updateds(vp, cred, p); error = VOP_FSYNC(vp, MNT_WAIT, p); } out: NFSEXITCODE(error); return (error); } /* * List Extended Atribute vnode op into an mbuf list. */ int nfsvno_listxattr(struct vnode *vp, uint64_t cookie, struct ucred *cred, struct thread *p, u_char **bufp, uint32_t *lenp, bool *eofp) { struct iovec iv; struct uio io; int error; size_t siz; *bufp = NULL; /* First, find out the size of the extended attribute. */ error = VOP_LISTEXTATTR(vp, EXTATTR_NAMESPACE_USER, NULL, &siz, cred, p); if (error != 0) return (NFSERR_NOXATTR); if (siz <= cookie) { *lenp = 0; *eofp = true; goto out; } if (siz > cookie + *lenp) { siz = cookie + *lenp; *eofp = false; } else *eofp = true; /* Just choose a sanity limit of 10Mbytes for malloc(M_TEMP). */ if (siz > 10 * 1024 * 1024) { error = NFSERR_XATTR2BIG; goto out; } *bufp = malloc(siz, M_TEMP, M_WAITOK); iv.iov_base = *bufp; iv.iov_len = siz; io.uio_iovcnt = 1; io.uio_iov = &iv; io.uio_offset = 0; io.uio_resid = siz; io.uio_rw = UIO_READ; io.uio_segflg = UIO_SYSSPACE; io.uio_td = p; #ifdef MAC error = mac_vnode_check_listextattr(cred, vp, EXTATTR_NAMESPACE_USER); if (error != 0) goto out; #endif error = VOP_LISTEXTATTR(vp, EXTATTR_NAMESPACE_USER, &io, NULL, cred, p); if (error != 0) goto out; if (io.uio_resid > 0) siz -= io.uio_resid; *lenp = siz; out: if (error != 0) { free(*bufp, M_TEMP); *bufp = NULL; } NFSEXITCODE(error); return (error); } /* * Trim trailing data off the mbuf list being built. */ void nfsm_trimtrailing(struct nfsrv_descript *nd, struct mbuf *mb, char *bpos, int bextpg, int bextpgsiz) { vm_page_t pg; int fullpgsiz, i; if (mb->m_next != NULL) { m_freem(mb->m_next); mb->m_next = NULL; } if ((mb->m_flags & M_EXTPG) != 0) { KASSERT(bextpg >= 0 && bextpg < mb->m_epg_npgs, ("nfsm_trimtrailing: bextpg out of range")); KASSERT(bpos == (char *)(void *) PHYS_TO_DMAP(mb->m_epg_pa[bextpg]) + PAGE_SIZE - bextpgsiz, ("nfsm_trimtrailing: bextpgsiz bad!")); /* First, get rid of any pages after this position. */ for (i = mb->m_epg_npgs - 1; i > bextpg; i--) { pg = PHYS_TO_VM_PAGE(mb->m_epg_pa[i]); vm_page_unwire_noq(pg); vm_page_free(pg); } mb->m_epg_npgs = bextpg + 1; if (bextpg == 0) fullpgsiz = PAGE_SIZE - mb->m_epg_1st_off; else fullpgsiz = PAGE_SIZE; mb->m_epg_last_len = fullpgsiz - bextpgsiz; mb->m_len = m_epg_pagelen(mb, 0, mb->m_epg_1st_off); for (i = 1; i < mb->m_epg_npgs; i++) mb->m_len += m_epg_pagelen(mb, i, 0); nd->nd_bextpgsiz = bextpgsiz; nd->nd_bextpg = bextpg; } else mb->m_len = bpos - mtod(mb, char *); nd->nd_mb = mb; nd->nd_bpos = bpos; } /* * Check to see if a put file handle operation should test for * NFSERR_WRONGSEC, although NFSv3 actually returns NFSERR_AUTHERR. * When Open is the next operation, NFSERR_WRONGSEC cannot be * replied for the Open cases that use a component. This can * be identified by the fact that the file handle's type is VDIR. */ bool nfsrv_checkwrongsec(struct nfsrv_descript *nd, int nextop, __enum_uint8(vtype) vtyp) { if ((nd->nd_flag & ND_NFSV4) == 0) return (true); if ((nd->nd_flag & ND_LASTOP) != 0) return (false); if (nextop == NFSV4OP_PUTROOTFH || nextop == NFSV4OP_PUTFH || nextop == NFSV4OP_PUTPUBFH || nextop == NFSV4OP_RESTOREFH || nextop == NFSV4OP_LOOKUP || nextop == NFSV4OP_LOOKUPP || nextop == NFSV4OP_SECINFO || nextop == NFSV4OP_SECINFONONAME) return (false); if (nextop == NFSV4OP_OPEN && vtyp == VDIR) return (false); return (true); } /* * Check DSs marked no space. */ void nfsrv_checknospc(void) { struct statfs *tsf; struct nfsdevice *ds; struct vnode **dvpp, **tdvpp, *dvp; char *devid, *tdevid; int cnt, error = 0, i; if (nfsrv_devidcnt <= 0) return; dvpp = mallocarray(nfsrv_devidcnt, sizeof(*dvpp), M_TEMP, M_WAITOK); devid = malloc(nfsrv_devidcnt * NFSX_V4DEVICEID, M_TEMP, M_WAITOK); tsf = malloc(sizeof(*tsf), M_TEMP, M_WAITOK); /* Get an array of the dvps for the DSs. */ tdvpp = dvpp; tdevid = devid; i = 0; NFSDDSLOCK(); /* First, search for matches for same file system. */ TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) { if (ds->nfsdev_nmp != NULL && ds->nfsdev_nospc) { if (++i > nfsrv_devidcnt) break; *tdvpp++ = ds->nfsdev_dvp; NFSBCOPY(ds->nfsdev_deviceid, tdevid, NFSX_V4DEVICEID); tdevid += NFSX_V4DEVICEID; } } NFSDDSUNLOCK(); /* Do a VFS_STATFS() for each of the DSs and clear no space. */ cnt = i; tdvpp = dvpp; tdevid = devid; for (i = 0; i < cnt && error == 0; i++) { dvp = *tdvpp++; error = VFS_STATFS(dvp->v_mount, tsf); if (error == 0 && tsf->f_bavail > 0) { NFSD_DEBUG(1, "nfsrv_checknospc: reset nospc\n"); nfsrv_marknospc(tdevid, false); } tdevid += NFSX_V4DEVICEID; } free(tsf, M_TEMP); free(dvpp, M_TEMP); free(devid, M_TEMP); } /* * Initialize everything that needs to be initialized for a vnet. */ static void nfsrv_vnetinit(const void *unused __unused) { nfsd_mntinit(); } VNET_SYSINIT(nfsrv_vnetinit, SI_SUB_VNET_DONE, SI_ORDER_ANY, nfsrv_vnetinit, NULL); /* * Clean up everything that is in a vnet and needs to be * done when the jail is destroyed or the module unloaded. */ static void nfsrv_cleanup(const void *unused __unused) { int i; NFSD_LOCK(); if (!NFSD_VNET(nfsrv_mntinited)) { NFSD_UNLOCK(); return; } NFSD_VNET(nfsrv_mntinited) = false; NFSD_UNLOCK(); /* Clean out all NFSv4 state. */ nfsrv_throwawayallstate(curthread); /* Clean the NFS server reply cache */ nfsrvd_cleancache(); /* Clean out v4root exports. */ if (NFSD_VNET(nfsv4root_mnt)->mnt_export != NULL) { vfs_free_addrlist(NFSD_VNET(nfsv4root_mnt)->mnt_export); free(NFSD_VNET(nfsv4root_mnt)->mnt_export, M_MOUNT); NFSD_VNET(nfsv4root_mnt)->mnt_export = NULL; } /* Free up the krpc server pool. */ if (NFSD_VNET(nfsrvd_pool) != NULL) svcpool_destroy(NFSD_VNET(nfsrvd_pool)); /* and get rid of the locks */ for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) { mtx_destroy(&NFSD_VNET(nfsrchash_table)[i].mtx); mtx_destroy(&NFSD_VNET(nfsrcahash_table)[i].mtx); } mtx_destroy(&NFSD_VNET(nfsv4root_mnt)->mnt_mtx); for (i = 0; i < nfsrv_sessionhashsize; i++) mtx_destroy(&NFSD_VNET(nfssessionhash)[i].mtx); lockdestroy(&NFSD_VNET(nfsv4root_mnt)->mnt_explock); free(NFSD_VNET(nfsrvudphashtbl), M_NFSRVCACHE); free(NFSD_VNET(nfsrchash_table), M_NFSRVCACHE); free(NFSD_VNET(nfsrcahash_table), M_NFSRVCACHE); free(NFSD_VNET(nfsclienthash), M_NFSDCLIENT); free(NFSD_VNET(nfslockhash), M_NFSDLOCKFILE); free(NFSD_VNET(nfssessionhash), M_NFSDSESSION); free(NFSD_VNET(nfsv4root_mnt), M_TEMP); NFSD_VNET(nfsv4root_mnt) = NULL; } VNET_SYSUNINIT(nfsrv_cleanup, SI_SUB_VNET_DONE, SI_ORDER_ANY, nfsrv_cleanup, NULL); extern int (*nfsd_call_nfsd)(struct thread *, struct nfssvc_args *); /* * Called once to initialize data structures... */ static int nfsd_modevent(module_t mod, int type, void *data) { int error = 0, i; static int loaded = 0; switch (type) { case MOD_LOAD: if (loaded) goto out; newnfs_portinit(); mtx_init(&nfsrc_udpmtx, "nfsuc", NULL, MTX_DEF); mtx_init(&nfs_v4root_mutex, "nfs4rt", NULL, MTX_DEF); mtx_init(&nfsrv_dontlistlock_mtx, "nfs4dnl", NULL, MTX_DEF); mtx_init(&nfsrv_recalllock_mtx, "nfs4rec", NULL, MTX_DEF); #ifdef VV_DISABLEDELEG vn_deleg_ops.vndeleg_recall = nfsd_recalldelegation; vn_deleg_ops.vndeleg_disable = nfsd_disabledelegation; #endif nfsd_call_nfsd = nfssvc_nfsd; loaded = 1; break; case MOD_UNLOAD: if (newnfs_numnfsd != 0) { error = EBUSY; break; } #ifdef VV_DISABLEDELEG vn_deleg_ops.vndeleg_recall = NULL; vn_deleg_ops.vndeleg_disable = NULL; #endif nfsd_call_nfsd = NULL; mtx_destroy(&nfsrc_udpmtx); mtx_destroy(&nfs_v4root_mutex); mtx_destroy(&nfsrv_dontlistlock_mtx); mtx_destroy(&nfsrv_recalllock_mtx); if (nfslayouthash != NULL) { for (i = 0; i < nfsrv_layouthashsize; i++) mtx_destroy(&nfslayouthash[i].mtx); free(nfslayouthash, M_NFSDSESSION); } loaded = 0; break; default: error = EOPNOTSUPP; break; } out: NFSEXITCODE(error); return (error); } static moduledata_t nfsd_mod = { "nfsd", nfsd_modevent, NULL, }; DECLARE_MODULE(nfsd, nfsd_mod, SI_SUB_VFS, SI_ORDER_ANY); /* So that loader and kldload(2) can find us, wherever we are.. */ MODULE_VERSION(nfsd, 1); MODULE_DEPEND(nfsd, nfscommon, 1, 1, 1); MODULE_DEPEND(nfsd, nfslockd, 1, 1, 1); MODULE_DEPEND(nfsd, krpc, 1, 1, 1); MODULE_DEPEND(nfsd, nfssvc, 1, 1, 1); diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index a881968b03be..921ea4887af1 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -1,6637 +1,6637 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 #include "opt_inet.h" #include "opt_inet6.h" /* * nfs version 2, 3 and 4 server calls to vnode ops * - these routines generally have 3 phases * 1 - break down and validate rpc request in mbuf list * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX() * function in nfsd_port.c * 3 - build the rpc reply in an mbuf list * For nfsv4, these functions are called for each Op within the Compound RPC. */ #include #include #include /* Global vars */ extern u_int32_t newnfs_false, newnfs_true; extern __enum_uint8(vtype) nv34tov_type[8]; extern struct timeval nfsboottime; extern int nfsrv_enable_crossmntpt; extern int nfsrv_statehashsize; extern int nfsrv_layouthashsize; extern time_t nfsdev_time; extern volatile int nfsrv_devidcnt; extern int nfsd_debuglevel; extern u_long sb_max_adj; extern int nfsrv_pnfsatime; extern int nfsrv_maxpnfsmirror; extern uint32_t nfs_srvmaxio; extern int nfsrv_issuedelegs; static int nfs_async = 0; SYSCTL_DECL(_vfs_nfsd); SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, "Tell client that writes were synced even though they were not"); extern int nfsrv_doflexfile; SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW, &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS"); static int nfsrv_linux42server = 1; SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW, &nfsrv_linux42server, 0, "Enable Linux style NFSv4.2 server (non-RFC compliant)"); static bool nfsrv_openaccess = true; SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW, &nfsrv_openaccess, 0, "Enable Linux style NFSv4 Open access check"); static char nfsrv_scope[NFSV4_OPAQUELIMIT]; SYSCTL_STRING(_vfs_nfsd, OID_AUTO, scope, CTLFLAG_RWTUN, &nfsrv_scope, NFSV4_OPAQUELIMIT, "Server scope"); static char nfsrv_owner_major[NFSV4_OPAQUELIMIT]; SYSCTL_STRING(_vfs_nfsd, OID_AUTO, owner_major, CTLFLAG_RWTUN, &nfsrv_owner_major, NFSV4_OPAQUELIMIT, "Server owner major"); static uint64_t nfsrv_owner_minor; SYSCTL_U64(_vfs_nfsd, OID_AUTO, owner_minor, CTLFLAG_RWTUN, &nfsrv_owner_minor, 0, "Server owner minor"); /* * Only enable this if all your exported file systems * (or pNFS DSs for the pNFS case) support VOP_ALLOCATE. */ static bool nfsrv_doallocate = false; SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, enable_v42allocate, CTLFLAG_RW, &nfsrv_doallocate, 0, "Enable NFSv4.2 Allocate operation"); static uint64_t nfsrv_maxcopyrange = SSIZE_MAX; SYSCTL_U64(_vfs_nfsd, OID_AUTO, maxcopyrange, CTLFLAG_RW, &nfsrv_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable"); /* * This list defines the GSS mechanisms supported. * (Don't ask me how you get these strings from the RFC stuff like * iso(1), org(3)... but someone did it, so I don't need to know.) */ static struct nfsgss_mechlist nfsgss_mechlist[] = { { 9, "\052\206\110\206\367\022\001\002\002", 11 }, { 0, "", 0 }, }; /* local functions */ static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, int pathlen); static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp); /* * nfs access service (not a part of NFS V2) */ int nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { u_int32_t *tl; int getret, error = 0; struct nfsvattr nva; u_int32_t testmode, nfsmode, supported = 0; accmode_t deletebit; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_postopattr(nd, 1, &nva); goto out; } NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); nfsmode = fxdr_unsigned(u_int32_t, *tl); if ((nd->nd_flag & ND_NFSV4) && (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE | NFSACCESS_XALIST))) { nd->nd_repstat = NFSERR_INVAL; vput(vp); goto out; } if (nfsmode & NFSACCESS_READ) { supported |= NFSACCESS_READ; if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) nfsmode &= ~NFSACCESS_READ; } if (nfsmode & NFSACCESS_MODIFY) { supported |= NFSACCESS_MODIFY; if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) nfsmode &= ~NFSACCESS_MODIFY; } if (nfsmode & NFSACCESS_EXTEND) { supported |= NFSACCESS_EXTEND; if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) nfsmode &= ~NFSACCESS_EXTEND; } if (nfsmode & NFSACCESS_XAREAD) { supported |= NFSACCESS_XAREAD; if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) nfsmode &= ~NFSACCESS_XAREAD; } if (nfsmode & NFSACCESS_XAWRITE) { supported |= NFSACCESS_XAWRITE; if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) nfsmode &= ~NFSACCESS_XAWRITE; } if (nfsmode & NFSACCESS_XALIST) { supported |= NFSACCESS_XALIST; if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) nfsmode &= ~NFSACCESS_XALIST; } if (nfsmode & NFSACCESS_DELETE) { supported |= NFSACCESS_DELETE; if (vp->v_type == VDIR) deletebit = VDELETE_CHILD; else deletebit = VDELETE; if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) nfsmode &= ~NFSACCESS_DELETE; } if (vp->v_type == VDIR) testmode = NFSACCESS_LOOKUP; else testmode = NFSACCESS_EXECUTE; if (nfsmode & testmode) { supported |= (nfsmode & testmode); if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) nfsmode &= ~testmode; } nfsmode &= supported; if (nd->nd_flag & ND_NFSV3) { getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); nfsrv_postopattr(nd, getret, &nva); } vput(vp); if (nd->nd_flag & ND_NFSV4) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(supported); } else NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(nfsmode); out: NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfs getattr service */ int nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { struct nfsvattr nva; fhandle_t fh; int at_root = 0, error = 0, ret, supports_nfsv4acls; struct nfsreferral *refp; nfsattrbit_t attrbits, tmpbits; struct mount *mp; struct vnode *tvp = NULL; struct vattr va; uint64_t mounted_on_fileno = 0; accmode_t accmode; struct thread *p = curthread; size_t atsiz; long pathval; bool has_hiddensystem, has_namedattr, xattrsupp; uint32_t clone_blksize; if (nd->nd_repstat) goto out; if (nd->nd_flag & ND_NFSV4) { error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error) { vput(vp); goto out; } /* * Check for a referral. */ refp = nfsv4root_getreferral(vp, NULL, 0); if (refp != NULL) { (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, &nd->nd_repstat); vput(vp); goto out; } if (nd->nd_repstat == 0) { accmode = 0; NFSSET_ATTRBIT(&tmpbits, &attrbits); /* * GETATTR with write-only attr time_access_set and time_modify_set * should return NFS4ERR_INVAL. */ if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) || NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){ error = NFSERR_INVAL; vput(vp); goto out; } if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); accmode |= VREAD_ACL; } if (NFSNONZERO_ATTRBIT(&tmpbits)) accmode |= VREAD_ATTRIBUTES; if (accmode != 0) nd->nd_repstat = nfsvno_accchk(vp, accmode, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, NULL); } } if (!nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); if (!nd->nd_repstat) { if (nd->nd_flag & ND_NFSV4) { if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) nd->nd_repstat = nfsvno_getfh(vp, &fh, p); if (!nd->nd_repstat) nd->nd_repstat = nfsrv_checkgetattr(nd, vp, &nva, &attrbits, p); if (nd->nd_repstat == 0) { supports_nfsv4acls = nfs_supportsnfsv4acls(vp); xattrsupp = false; if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_XATTRSUPPORT)) { ret = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, "xxx", NULL, &atsiz, nd->nd_cred, p); xattrsupp = ret != EOPNOTSUPP; } if (VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM, &pathval) != 0) pathval = 0; has_hiddensystem = pathval > 0; pathval = 0; if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_NAMEDATTR) && VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR, &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 && (vp->v_vflag & VV_ROOT) != 0 && vp != rootvnode) { tvp = mp->mnt_vnodecovered; - VREF(tvp); + vref(tvp); at_root = 1; } else at_root = 0; vfs_ref(mp); NFSVOPUNLOCK(vp); if (at_root != 0) { if ((nd->nd_repstat = NFSVOPLOCK(tvp, LK_SHARED)) == 0) { nd->nd_repstat = VOP_GETATTR( tvp, &va, nd->nd_cred); vput(tvp); } else vrele(tvp); if (nd->nd_repstat == 0) mounted_on_fileno = (uint64_t) va.va_fileid; else at_root = 0; } if (nd->nd_repstat == 0) nd->nd_repstat = vfs_busy(mp, 0); vfs_rel(mp); if (nd->nd_repstat == 0) { (void)nfsvno_fillattr(nd, mp, vp, &nva, &fh, 0, &attrbits, nd->nd_cred, p, isdgram, 1, supports_nfsv4acls, at_root, mounted_on_fileno, xattrsupp, has_hiddensystem, has_namedattr, clone_blksize); vfs_unbusy(mp); } vrele(vp); } else vput(vp); } else { nfsrv_fillattr(nd, &nva); vput(vp); } } else { vput(vp); } out: NFSEXITCODE2(error, nd); return (error); } /* * nfs setattr service */ int nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { struct nfsvattr nva, nva2; u_int32_t *tl; int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; int gotproxystateid; struct timespec guard = { 0, 0 }; nfsattrbit_t attrbits, retbits; nfsv4stateid_t stateid; NFSACL_T *aclp = NULL; struct thread *p = curthread; NFSZERO_ATTRBIT(&retbits); if (nd->nd_repstat) { nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); goto out; } #ifdef NFS4_ACL_EXTATTR_NAME aclp = acl_alloc(M_WAITOK); aclp->acl_cnt = 0; #endif gotproxystateid = 0; NFSVNO_ATTRINIT(&nva); if (nd->nd_flag & ND_NFSV4) { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); stateid.other[0] = *tl++; stateid.other[1] = *tl++; stateid.other[2] = *tl; if (stateid.other[0] == 0x55555555 && stateid.other[1] == 0x55555555 && stateid.other[2] == 0x55555555 && stateid.seqid == 0xffffffff) gotproxystateid = 1; } error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p); if (error) goto nfsmout; /* For NFSv4, only va_uid and va_flags is used from nva2. */ NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN); NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM); preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits); if (!nd->nd_repstat) nd->nd_repstat = preat_ret; NFSZERO_ATTRBIT(&retbits); if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); gcheck = fxdr_unsigned(int, *tl); if (gcheck) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); fxdr_nfsv3time(tl, &guard); } if (!nd->nd_repstat && gcheck && (nva2.na_ctime.tv_sec != guard.tv_sec || nva2.na_ctime.tv_nsec != guard.tv_nsec)) nd->nd_repstat = NFSERR_NOT_SYNC; if (nd->nd_repstat) { vput(vp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); goto out; } } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); /* * Now that we have all the fields, lets do it. * If the size is being changed write access is required, otherwise * just check for a read only file system. */ if (!nd->nd_repstat) { if (NFSVNO_NOTSETSIZE(&nva)) { if (NFSVNO_EXRDONLY(exp) || (vp->v_mount->mnt_flag & MNT_RDONLY)) nd->nd_repstat = EROFS; } else { if (vp->v_type != VREG) nd->nd_repstat = EINVAL; else if (nva2.na_uid != nd->nd_cred->cr_uid || NFSVNO_EXSTRICTACCESS(exp)) nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, NULL); } } /* * Proxy operations from the MDS are allowed via the all 0s special * stateid. */ if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 && gotproxystateid == 0) nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, &nva, &attrbits, exp, p); if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { u_long oldflags; oldflags = nva2.na_flags; /* * For V4, try setting the attributes in sets, so that the * reply bitmap will be correct for an error case. */ if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { NFSVNO_ATTRINIT(&nva2); NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, exp); if (!nd->nd_repstat) { if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); } } if (!nd->nd_repstat && NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { NFSVNO_ATTRINIT(&nva2); NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, exp); if (!nd->nd_repstat) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); } if (!nd->nd_repstat && (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { NFSVNO_ATTRINIT(&nva2); NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); if (nva.na_vaflags & VA_UTIMES_NULL) { nva2.na_vaflags |= VA_UTIMES_NULL; NFSVNO_SETACTIVE(&nva2, vaflags); } nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, exp); if (!nd->nd_repstat) { if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); } } if (!nd->nd_repstat && NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE)) { NFSVNO_ATTRINIT(&nva2); NFSVNO_SETATTRVAL(&nva2, btime, nva.na_btime); nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, exp); if (!nd->nd_repstat) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMECREATE); } if (!nd->nd_repstat && (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) || NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) { NFSVNO_ATTRINIT(&nva2); NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, exp); if (!nd->nd_repstat) { if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED)) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED); } } if (!nd->nd_repstat && (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN) || NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))) { if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) { if ((nva.na_flags & UF_HIDDEN) != 0) oldflags |= UF_HIDDEN; else oldflags &= ~UF_HIDDEN; } if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM)) { if ((nva.na_flags & UF_SYSTEM) != 0) oldflags |= UF_SYSTEM; else oldflags &= ~UF_SYSTEM; } NFSVNO_ATTRINIT(&nva2); NFSVNO_SETATTRVAL(&nva2, flags, oldflags); nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, exp); if (!nd->nd_repstat) { if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN); if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM)) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM); } } #ifdef NFS4_ACL_EXTATTR_NAME if (!nd->nd_repstat && aclp->acl_cnt > 0 && NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); if (!nd->nd_repstat) NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); } #endif } else if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, exp); } if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); if (!nd->nd_repstat) nd->nd_repstat = postat_ret; } vput(vp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif if (nd->nd_flag & ND_NFSV3) nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); else if (nd->nd_flag & ND_NFSV4) (void) nfsrv_putattrbit(nd, &retbits); else if (!nd->nd_repstat) nfsrv_fillattr(nd, &nva); out: NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif if (nd->nd_flag & ND_NFSV4) { /* * For all nd_repstat, the V4 reply includes a bitmap, * even NFSERR_BADXDR, which is what this will end up * returning. */ (void) nfsrv_putattrbit(nd, &retbits); } NFSEXITCODE2(error, nd); return (error); } /* * nfs lookup rpc * (Also performs lookup parent for v4) */ int nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) { struct nameidata named; vnode_t vp, dirp = NULL; int error = 0, dattr_ret = 1; struct nfsvattr nva, dattr; char *bufp; u_long *hashp; struct thread *p = curthread; struct componentname *cnp; short irflag; if (nd->nd_repstat) { nfsrv_postopattr(nd, dattr_ret, &dattr); goto out; } /* * For some reason, if dp is a symlink, the error * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. */ if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { nd->nd_repstat = NFSERR_SYMLINK; vrele(dp); goto out; } cnp = &named.ni_cnd; irflag = vn_irflag_read(dp); if ((irflag & VIRF_NAMEDDIR) != 0) NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF | OPENNAMED); else NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) { vrele(dp); nfsvno_relpathbuf(&named); goto out; } if (!nd->nd_repstat) { /* Don't set OPENNAMED for Lookupp (".."). */ if (cnp->cn_namelen == 2 && *cnp->cn_pnbuf == '.' && *(cnp->cn_pnbuf + 1) == '.') cnp->cn_flags &= ~OPENNAMED; nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); } else { vrele(dp); nfsvno_relpathbuf(&named); } if (nd->nd_repstat) { if (dirp) { if (nd->nd_flag & ND_NFSV3) dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0, NULL); vrele(dirp); } if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, dattr_ret, &dattr); goto out; } nfsvno_relpathbuf(&named); vp = named.ni_vp; if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && vp->v_type != VDIR && vp->v_type != VLNK) /* * Only allow lookup of VDIR and VLNK for traversal of * non-exported volumes during NFSv4 mounting. */ nd->nd_repstat = ENOENT; if (nd->nd_repstat == 0) { nd->nd_repstat = nfsvno_getfh(vp, fhp, p); /* * EOPNOTSUPP indicates the file system cannot be exported, * so just pretend the entry does not exist. */ if (nd->nd_repstat == EOPNOTSUPP) nd->nd_repstat = ENOENT; } if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); if (vpp != NULL && nd->nd_repstat == 0) *vpp = vp; else vput(vp); if (dirp) { if (nd->nd_flag & ND_NFSV3) dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0, NULL); vrele(dirp); } if (nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, dattr_ret, &dattr); goto out; } if (nd->nd_flag & ND_NFSV2) { (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0); nfsrv_fillattr(nd, &nva); } else if (nd->nd_flag & ND_NFSV3) { (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0); nfsrv_postopattr(nd, 0, &nva); nfsrv_postopattr(nd, dattr_ret, &dattr); } out: NFSEXITCODE2(error, nd); return (error); } /* * nfs readlink service */ int nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; struct mbuf *mp = NULL, *mpend = NULL; int getret = 1, len; struct nfsvattr nva; struct thread *p = curthread; uint16_t off; if (nd->nd_repstat) { nfsrv_postopattr(nd, getret, &nva); goto out; } if (vp->v_type != VLNK) { if (nd->nd_flag & ND_NFSV2) nd->nd_repstat = ENXIO; else nd->nd_repstat = EINVAL; } if (nd->nd_repstat == 0) { if ((nd->nd_flag & ND_EXTPG) != 0) nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, nd->nd_maxextsiz, p, &mp, &mpend, &len); else nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, 0, p, &mp, &mpend, &len); } if (nd->nd_flag & ND_NFSV3) getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); vput(vp); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &nva); if (nd->nd_repstat) goto out; NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(len); if (mp != NULL) { nd->nd_mb->m_next = mp; nd->nd_mb = mpend; if ((mpend->m_flags & M_EXTPG) != 0) { nd->nd_bextpg = mpend->m_epg_npgs - 1; nd->nd_bpos = (char *)(void *) PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0; nd->nd_bpos += off + mpend->m_epg_last_len; nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len - off; } else nd->nd_bpos = mtod(mpend, char *) + mpend->m_len; } out: NFSEXITCODE2(0, nd); return (0); } /* * nfs read service */ int nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { u_int32_t *tl; int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0; struct mbuf *m2, *m3; struct nfsvattr nva; off_t off = 0x0; struct nfsstate st, *stp = &st; struct nfslock lo, *lop = &lo; nfsv4stateid_t stateid; nfsquad_t clientid; struct thread *p = curthread; uint16_t poff; if (nd->nd_repstat) { nfsrv_postopattr(nd, getret, &nva); goto out; } if (nd->nd_flag & ND_NFSV2) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); off = (off_t)fxdr_unsigned(u_int32_t, *tl++); reqlen = fxdr_unsigned(int, *tl); } else if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); off = fxdr_hyper(tl); tl += 2; reqlen = fxdr_unsigned(int, *tl); } else { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); reqlen = fxdr_unsigned(int, *(tl + 6)); } if (reqlen > NFS_SRVMAXDATA(nd)) { reqlen = NFS_SRVMAXDATA(nd); } else if (reqlen < 0) { error = EBADRPC; goto nfsmout; } gotproxystateid = 0; if (nd->nd_flag & ND_NFSV4) { stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); lop->lo_flags = NFSLCK_READ; stp->ls_ownerlen = 0; stp->ls_op = NULL; stp->ls_uid = nd->nd_cred->cr_uid; stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK1 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } stp->ls_stateid.other[2] = *tl++; /* * Don't allow the client to use a special stateid for a DS op. */ if ((nd->nd_flag & ND_DSSERVER) != 0 && ((stp->ls_stateid.other[0] == 0x0 && stp->ls_stateid.other[1] == 0x0 && stp->ls_stateid.other[2] == 0x0) || (stp->ls_stateid.other[0] == 0xffffffff && stp->ls_stateid.other[1] == 0xffffffff && stp->ls_stateid.other[2] == 0xffffffff) || stp->ls_stateid.seqid != 0)) nd->nd_repstat = NFSERR_BADSTATEID; /* However, allow the proxy stateid. */ if (stp->ls_stateid.seqid == 0xffffffff && stp->ls_stateid.other[0] == 0x55555555 && stp->ls_stateid.other[1] == 0x55555555 && stp->ls_stateid.other[2] == 0x55555555) gotproxystateid = 1; off = fxdr_hyper(tl); lop->lo_first = off; tl += 2; lop->lo_end = off + reqlen; /* * Paranoia, just in case it wraps around. */ if (lop->lo_end < off) lop->lo_end = NFS64BITSSET; } if (vp->v_type != VREG) { if (nd->nd_flag & ND_NFSV3) nd->nd_repstat = EINVAL; else nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR : EINVAL; } getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); if (!nd->nd_repstat) nd->nd_repstat = getret; if (!nd->nd_repstat && (nva.na_uid != nd->nd_cred->cr_uid || NFSVNO_EXSTRICTACCESS(exp))) { nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); if (nd->nd_repstat) nd->nd_repstat = nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); } /* * DS reads are marked by ND_DSSERVER or use the proxy special * stateid. */ if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == ND_NFSV4 && gotproxystateid == 0) nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, &stateid, exp, nd, p); if (nd->nd_repstat) { vput(vp); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &nva); goto out; } if (off >= nva.na_size) { cnt = 0; eof = 1; } else if (reqlen == 0) cnt = 0; else if ((off + reqlen) >= nva.na_size) { cnt = nva.na_size - off; eof = 1; } else cnt = reqlen; m3 = NULL; if (cnt > 0) { /* * If cnt > MCLBYTES and the reply will not be saved, use * ext_pgs mbufs for TLS. * For NFSv4.0, we do not know for sure if the reply will * be saved, so do not use ext_pgs mbufs for NFSv4.0. * Always use ext_pgs mbufs if ND_EXTPG is set. */ if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES && (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS && (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4)) nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, nd->nd_maxextsiz, p, &m3, &m2); else nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, 0, p, &m3, &m2); if (!(nd->nd_flag & ND_NFSV4)) { getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); if (!nd->nd_repstat) nd->nd_repstat = getret; } if (nd->nd_repstat) { vput(vp); if (m3) m_freem(m3); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &nva); goto out; } } vput(vp); if (nd->nd_flag & ND_NFSV2) { nfsrv_fillattr(nd, &nva); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); } else { if (nd->nd_flag & ND_NFSV3) { nfsrv_postopattr(nd, getret, &nva); NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(cnt); } else NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); if (eof) *tl++ = newnfs_true; else *tl++ = newnfs_false; } *tl = txdr_unsigned(cnt); if (m3) { nd->nd_mb->m_next = m3; nd->nd_mb = m2; if ((m2->m_flags & M_EXTPG) != 0) { nd->nd_flag |= ND_EXTPG; nd->nd_bextpg = m2->m_epg_npgs - 1; nd->nd_bpos = (char *)(void *) PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]); poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0; nd->nd_bpos += poff + m2->m_epg_last_len; nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len - poff; } else nd->nd_bpos = mtod(m2, char *) + m2->m_len; } out: NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfs write service */ int nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { u_int32_t *tl; struct nfsvattr nva, forat; int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; int gotproxystateid, stable = NFSWRITE_FILESYNC; off_t off; struct nfsstate st, *stp = &st; struct nfslock lo, *lop = &lo; nfsv4stateid_t stateid; nfsquad_t clientid; nfsattrbit_t attrbits; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); goto out; } gotproxystateid = 0; if (nd->nd_flag & ND_NFSV2) { NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); off = (off_t)fxdr_unsigned(u_int32_t, *++tl); tl += 2; retlen = len = fxdr_unsigned(int32_t, *tl); } else if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); off = fxdr_hyper(tl); tl += 3; stable = fxdr_unsigned(int, *tl++); retlen = len = fxdr_unsigned(int32_t, *tl); } else { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); lop->lo_flags = NFSLCK_WRITE; stp->ls_ownerlen = 0; stp->ls_op = NULL; stp->ls_uid = nd->nd_cred->cr_uid; stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK2 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } stp->ls_stateid.other[2] = *tl++; /* * Don't allow the client to use a special stateid for a DS op. */ if ((nd->nd_flag & ND_DSSERVER) != 0 && ((stp->ls_stateid.other[0] == 0x0 && stp->ls_stateid.other[1] == 0x0 && stp->ls_stateid.other[2] == 0x0) || (stp->ls_stateid.other[0] == 0xffffffff && stp->ls_stateid.other[1] == 0xffffffff && stp->ls_stateid.other[2] == 0xffffffff) || stp->ls_stateid.seqid != 0)) nd->nd_repstat = NFSERR_BADSTATEID; /* However, allow the proxy stateid. */ if (stp->ls_stateid.seqid == 0xffffffff && stp->ls_stateid.other[0] == 0x55555555 && stp->ls_stateid.other[1] == 0x55555555 && stp->ls_stateid.other[2] == 0x55555555) gotproxystateid = 1; off = fxdr_hyper(tl); lop->lo_first = off; tl += 2; stable = fxdr_unsigned(int, *tl++); retlen = len = fxdr_unsigned(int32_t, *tl); lop->lo_end = off + len; /* * Paranoia, just in case it wraps around, which shouldn't * ever happen anyhow. */ if (lop->lo_end < lop->lo_first) lop->lo_end = NFS64BITSSET; } if (retlen > nfs_srvmaxio || retlen < 0) nd->nd_repstat = EIO; if (vp->v_type != VREG && !nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) nd->nd_repstat = EINVAL; else nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR : EINVAL; } NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits); if (!nd->nd_repstat) nd->nd_repstat = forat_ret; if (!nd->nd_repstat && (forat.na_uid != nd->nd_cred->cr_uid || NFSVNO_EXSTRICTACCESS(exp))) nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); /* * DS reads are marked by ND_DSSERVER or use the proxy special * stateid. */ if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == ND_NFSV4 && gotproxystateid == 0) nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, &stateid, exp, nd, p); if (nd->nd_repstat) { vput(vp); if (nd->nd_flag & ND_NFSV3) nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); goto out; } /* * For NFS Version 2, it is not obvious what a write of zero length * should do, but I might as well be consistent with Version 3, * which is to return ok so long as there are no permission problems. */ if (retlen > 0) { nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable, nd->nd_md, nd->nd_dpos, nd->nd_cred, p); error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); if (error) goto nfsmout; } if (nd->nd_flag & ND_NFSV4) aftat_ret = 0; else aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); vput(vp); if (!nd->nd_repstat) nd->nd_repstat = aftat_ret; if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { if (nd->nd_flag & ND_NFSV3) nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); if (nd->nd_repstat) goto out; NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(retlen); /* * If nfs_async is set, then pretend the write was FILESYNC. * Warning: Doing this violates RFC1813 and runs a risk * of data written by a client being lost when the server * crashes/reboots. */ if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) *tl++ = txdr_unsigned(stable); else *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); /* * Actually, there is no need to txdr these fields, * but it may make the values more human readable, * for debugging purposes. */ *tl++ = txdr_unsigned(nfsboottime.tv_sec); *tl = txdr_unsigned(nfsboottime.tv_usec); } else if (!nd->nd_repstat) nfsrv_fillattr(nd, &nva); out: NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) * now does a truncate to 0 length via. setattr if it already exists * The core creation routine has been extracted out into nfsrv_creatsub(), * so it can also be used by nfsrv_open() for V4. */ int nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, vnode_t dp, struct nfsexstuff *exp) { struct nfsvattr nva, dirfor, diraft; struct nfsv2_sattr *sp; struct nameidata named; u_int32_t *tl; int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; NFSDEV_T rdev = 0; vnode_t vp = NULL, dirp = NULL; fhandle_t fh; char *bufp; u_long *hashp; __enum_uint8(vtype) vtyp; int32_t cverf[2], tverf[2] = { 0, 0 }; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | LOCKLEAF | NOCACHE); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) goto nfsmout; if (!nd->nd_repstat) { NFSVNO_ATTRINIT(&nva); if (nd->nd_flag & ND_NFSV2) { NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); if (vtyp == VNON) vtyp = VREG; NFSVNO_SETATTRVAL(&nva, type, vtyp); NFSVNO_SETATTRVAL(&nva, mode, nfstov_mode(sp->sa_mode)); switch (nva.na_type) { case VREG: tsize = fxdr_unsigned(int32_t, sp->sa_size); if (tsize != -1) NFSVNO_SETATTRVAL(&nva, size, (u_quad_t)tsize); break; case VCHR: case VBLK: case VFIFO: rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); break; default: break; } } else { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); how = fxdr_unsigned(int, *tl); switch (how) { case NFSCREATE_GUARDED: case NFSCREATE_UNCHECKED: error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); if (error) goto nfsmout; break; case NFSCREATE_EXCLUSIVE: NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); cverf[0] = *tl++; cverf[1] = *tl; exclusive_flag = 1; break; } NFSVNO_SETATTRVAL(&nva, type, VREG); } } if (nd->nd_repstat) { nfsvno_relpathbuf(&named); if (nd->nd_flag & ND_NFSV3) { dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1, NULL); nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); } vput(dp); goto out; } nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); if (dirp) { if (nd->nd_flag & ND_NFSV2) { vrele(dirp); dirp = NULL; } else { dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); } } if (nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); if (dirp) vrele(dirp); goto out; } if (!(nd->nd_flag & ND_NFSV2)) { switch (how) { case NFSCREATE_GUARDED: if (named.ni_vp) nd->nd_repstat = EEXIST; break; case NFSCREATE_UNCHECKED: break; case NFSCREATE_EXCLUSIVE: if (named.ni_vp == NULL) NFSVNO_SETATTRVAL(&nva, mode, 0); break; } } /* * Iff doesn't exist, create it * otherwise just truncate to 0 length * should I set the mode too ? */ nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, &exclusive_flag, cverf, rdev, exp); if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_getfh(vp, &fh, p); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); vput(vp); if (!nd->nd_repstat) { tverf[0] = nva.na_atime.tv_sec; tverf[1] = nva.na_atime.tv_nsec; } } if (nd->nd_flag & ND_NFSV2) { if (!nd->nd_repstat) { (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0); nfsrv_fillattr(nd, &nva); } } else { if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] || cverf[1] != tverf[1])) nd->nd_repstat = EEXIST; diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); vrele(dirp); if (!nd->nd_repstat) { (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 1); nfsrv_postopattr(nd, 0, &nva); } nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); } out: NFSEXITCODE2(0, nd); return (0); nfsmout: vput(dp); nfsvno_relpathbuf(&named); NFSEXITCODE2(error, nd); return (error); } /* * nfs v3 mknod service (and v4 create) */ int nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) { struct nfsvattr nva, dirfor, diraft; u_int32_t *tl; struct nameidata named; int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; u_int32_t major, minor; __enum_uint8(vtype) vtyp = VNON; nfstype nfs4type = NFNON; vnode_t vp, dirp = NULL; nfsattrbit_t attrbits; char *bufp = NULL, *pathcp = NULL; u_long *hashp, cnflags; NFSACL_T *aclp = NULL; struct thread *p = curthread; NFSVNO_ATTRINIT(&nva); cnflags = LOCKPARENT; if (nd->nd_repstat) { nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } #ifdef NFS4_ACL_EXTATTR_NAME aclp = acl_alloc(M_WAITOK); aclp->acl_cnt = 0; #endif /* * For V4, the creation stuff is here, Yuck! */ if (nd->nd_flag & ND_NFSV4) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); vtyp = nfsv34tov_type(*tl); nfs4type = fxdr_unsigned(nfstype, *tl); if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0) { /* * Don't allow creation of non-regular file objects * in a named attribute directory. */ nd->nd_repstat = NFSERR_INVAL; vrele(dp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif goto out; } switch (nfs4type) { case NFLNK: error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); if (error) goto nfsmout; break; case NFCHR: case NFBLK: NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); major = fxdr_unsigned(u_int32_t, *tl++); minor = fxdr_unsigned(u_int32_t, *tl); nva.na_rdev = NFSMAKEDEV(major, minor); break; case NFSOCK: case NFFIFO: break; case NFDIR: cnflags = LOCKPARENT; break; default: nd->nd_repstat = NFSERR_BADTYPE; vrele(dp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif goto out; } } NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) goto nfsmout; if (!nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); vtyp = nfsv34tov_type(*tl); } error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p); if (error) goto nfsmout; nva.na_type = vtyp; if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && (vtyp == VCHR || vtyp == VBLK)) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); major = fxdr_unsigned(u_int32_t, *tl++); minor = fxdr_unsigned(u_int32_t, *tl); nva.na_rdev = NFSMAKEDEV(major, minor); } } dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && dirfor.na_gid == nva.na_gid) NFSVNO_UNSET(&nva, gid); nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); } if (nd->nd_repstat) { vrele(dp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif nfsvno_relpathbuf(&named); if (pathcp) free(pathcp, M_TEMP); if (nd->nd_flag & ND_NFSV3) nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } /* * Yuck! For V4, mkdir and link are here and some V4 clients don't fill * in va_mode, so we'll have to set a default here. */ if (NFSVNO_NOTSETMODE(&nva)) { if (vtyp == VLNK) nva.na_mode = 0755; else nva.na_mode = 0400; } if (vtyp == VDIR) named.ni_cnd.cn_flags |= WILLBEDIR; nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); if (nd->nd_repstat) { if (dirp) { if (nd->nd_flag & ND_NFSV3) dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); vrele(dirp); } #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif if (nd->nd_flag & ND_NFSV3) nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } if (dirp) dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { if (vtyp == VDIR) { nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, exp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif goto out; } else if (vtyp == VLNK) { nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, exp, pathcp, pathlen); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif free(pathcp, M_TEMP); goto out; } } nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); if (!nd->nd_repstat) { vp = named.ni_vp; nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); nd->nd_repstat = nfsvno_getfh(vp, fhp, p); if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); if (vpp != NULL && nd->nd_repstat == 0) { NFSVOPUNLOCK(vp); *vpp = vp; } else vput(vp); } diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); vrele(dirp); if (!nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) { (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1); nfsrv_postopattr(nd, 0, &nva); } else { NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = newnfs_false; txdr_hyper(dirfor.na_filerev, tl); tl += 2; txdr_hyper(diraft.na_filerev, tl); (void) nfsrv_putattrbit(nd, &attrbits); } } if (nd->nd_flag & ND_NFSV3) nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif out: NFSEXITCODE2(0, nd); return (0); nfsmout: vrele(dp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif if (bufp) nfsvno_relpathbuf(&named); if (pathcp) free(pathcp, M_TEMP); NFSEXITCODE2(error, nd); return (error); } /* * nfs remove service */ int nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, vnode_t dp, struct nfsexstuff *exp) { struct nameidata named; u_int32_t *tl; int error = 0, dirfor_ret = 1, diraft_ret = 1; vnode_t dirp = NULL; struct nfsvattr dirfor, diraft; char *bufp; u_long *hashp; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, LOCKPARENT | LOCKLEAF); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) { vput(dp); nfsvno_relpathbuf(&named); goto out; } if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); } else { vput(dp); nfsvno_relpathbuf(&named); } if (dirp) { if (!(nd->nd_flag & ND_NFSV2)) { dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); } else { vrele(dirp); dirp = NULL; } } if (!nd->nd_repstat) { if (nd->nd_flag & ND_NFSV4) { if (named.ni_vp->v_type == VDIR) nd->nd_repstat = nfsvno_rmdirsub(&named, 1, nd->nd_cred, p, exp); else nd->nd_repstat = nfsvno_removesub(&named, true, nd, p, exp); } else if (nd->nd_procnum == NFSPROC_RMDIR) { nd->nd_repstat = nfsvno_rmdirsub(&named, 0, nd->nd_cred, p, exp); } else { nd->nd_repstat = nfsvno_removesub(&named, false, nd, p, exp); } } if (!(nd->nd_flag & ND_NFSV2)) { if (dirp) { diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); vrele(dirp); } if (nd->nd_flag & ND_NFSV3) { nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); } else if (!nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = newnfs_false; txdr_hyper(dirfor.na_filerev, tl); tl += 2; txdr_hyper(diraft.na_filerev, tl); } } out: NFSEXITCODE2(error, nd); return (error); } /* * nfs rename service */ int nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp) { u_int32_t *tl; int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; int tdirfor_ret = 1, tdiraft_ret = 1; struct nameidata fromnd, tond; vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; struct nfsexstuff tnes; struct nfsrvfh tfh; char *bufp, *tbufp = NULL; u_long *hashp; fhandle_t fh; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); goto out; } if (!(nd->nd_flag & ND_NFSV2)) fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL); tond.ni_cnd.cn_nameiop = 0; tond.ni_startdir = NULL; NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT); nfsvno_setpathbuf(&fromnd, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); if (error) { vput(dp); if (todp) vrele(todp); nfsvno_relpathbuf(&fromnd); goto out; } /* * Unlock dp in this code section, so it is unlocked before * tdp gets locked. This avoids a potential LOR if tdp is the * parent directory of dp. */ if (nd->nd_flag & ND_NFSV4) { tdp = todp; tnes = *toexp; if (dp != tdp) { NFSVOPUNLOCK(dp); /* Might lock tdp. */ tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0, NULL); } else { tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, NULL); NFSVOPUNLOCK(dp); } } else { tfh.nfsrvfh_len = 0; error = nfsrv_mtofh(nd, &tfh); if (error == 0) error = nfsvno_getfh(dp, &fh, p); if (error) { vput(dp); /* todp is always NULL except NFSv4 */ nfsvno_relpathbuf(&fromnd); goto out; } /* If this is the same file handle, just VREF() the vnode. */ if (!NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { - VREF(dp); + vref(dp); tdp = dp; tnes = *exp; tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, NULL); NFSVOPUNLOCK(dp); } else { NFSVOPUNLOCK(dp); nd->nd_cred->cr_uid = nd->nd_saveduid; nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 0, -1); /* Locks tdp. */ if (tdp) { tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, NULL); NFSVOPUNLOCK(tdp); } } } NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE); nfsvno_setpathbuf(&tond, &tbufp, &hashp); if (!nd->nd_repstat) { error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); if (error) { if (tdp) vrele(tdp); vrele(dp); nfsvno_relpathbuf(&fromnd); nfsvno_relpathbuf(&tond); goto out; } } if (nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) { nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); } if (tdp) vrele(tdp); vrele(dp); nfsvno_relpathbuf(&fromnd); nfsvno_relpathbuf(&tond); goto out; } /* * Done parsing, now down to business. */ nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, &fdirp); if (nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) { nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); } if (fdirp) vrele(fdirp); if (tdp) vrele(tdp); nfsvno_relpathbuf(&tond); goto out; } if (fromnd.ni_vp->v_type == VDIR) tond.ni_cnd.cn_flags |= WILLBEDIR; nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, &tdirp); nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd, p); if (fdirp) fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL); if (tdirp) tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL); if (fdirp) vrele(fdirp); if (tdirp) vrele(tdirp); if (nd->nd_flag & ND_NFSV3) { nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); *tl++ = newnfs_false; txdr_hyper(fdirfor.na_filerev, tl); tl += 2; txdr_hyper(fdiraft.na_filerev, tl); tl += 2; *tl++ = newnfs_false; txdr_hyper(tdirfor.na_filerev, tl); tl += 2; txdr_hyper(tdiraft.na_filerev, tl); } out: NFSEXITCODE2(error, nd); return (error); } /* * nfs link service */ int nfsrvd_link(struct nfsrv_descript *nd, int isdgram, vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) { struct nameidata named; u_int32_t *tl; int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; vnode_t dirp = NULL, dp = NULL; struct nfsvattr dirfor, diraft, at; struct nfsexstuff tnes; struct nfsrvfh dfh; char *bufp; u_long *hashp; struct thread *p = curthread; nfsquad_t clientid; if (nd->nd_repstat) { nfsrv_postopattr(nd, getret, &at); nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } if ((vn_irflag_read(vp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0 || (tovp != NULL && (vn_irflag_read(tovp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0)) { nd->nd_repstat = NFSERR_INVAL; if (tovp != NULL) vrele(tovp); } NFSVOPUNLOCK(vp); if (!nd->nd_repstat && vp->v_type == VDIR) { if (nd->nd_flag & ND_NFSV4) nd->nd_repstat = NFSERR_ISDIR; else nd->nd_repstat = NFSERR_INVAL; if (tovp) vrele(tovp); } if (!nd->nd_repstat) { if (nd->nd_flag & ND_NFSV4) { dp = tovp; tnes = *toexp; } else { error = nfsrv_mtofh(nd, &dfh); if (error) { vrele(vp); /* tovp is always NULL unless NFSv4 */ goto out; } nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0, -1); if (dp) NFSVOPUNLOCK(dp); } } NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE); if (!nd->nd_repstat) { nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) { vrele(vp); if (dp) vrele(dp); nfsvno_relpathbuf(&named); goto out; } if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, &dirp); } else { if (dp) vrele(dp); nfsvno_relpathbuf(&named); } } if (dirp) { if (nd->nd_flag & ND_NFSV2) { vrele(dirp); dirp = NULL; } else { dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); } } if (!nd->nd_repstat) { clientid.qval = 0; if ((nd->nd_flag & (ND_IMPLIEDCLID | ND_NFSV41)) == (ND_IMPLIEDCLID | ND_NFSV41)) clientid.qval = nd->nd_clientid.qval; nd->nd_repstat = nfsvno_link(&named, vp, clientid, nd->nd_cred, p, exp); } if (nd->nd_flag & ND_NFSV3) getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL); if (dirp) { diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); vrele(dirp); } vrele(vp); if (nd->nd_flag & ND_NFSV3) { nfsrv_postopattr(nd, getret, &at); nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = newnfs_false; txdr_hyper(dirfor.na_filerev, tl); tl += 2; txdr_hyper(diraft.na_filerev, tl); } out: NFSEXITCODE2(error, nd); return (error); } /* * nfs symbolic link service */ int nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) { struct nfsvattr nva, dirfor, diraft; struct nameidata named; int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; vnode_t dirp = NULL; char *bufp, *pathcp = NULL; u_long *hashp; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } if (vpp) *vpp = NULL; NFSVNO_ATTRINIT(&nva); NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (!error && !nd->nd_repstat) error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); if (error) { vrele(dp); nfsvno_relpathbuf(&named); goto out; } if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); } else { vrele(dp); nfsvno_relpathbuf(&named); } if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { vrele(dirp); dirp = NULL; } /* * And call nfsrvd_symlinksub() to do the common code. It will * return EBADRPC upon a parsing error, 0 otherwise. */ if (!nd->nd_repstat) { if (dirp != NULL) dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, pathcp, pathlen); } else if (dirp != NULL) { dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); vrele(dirp); } if (pathcp) free(pathcp, M_TEMP); if (nd->nd_flag & ND_NFSV3) { if (!nd->nd_repstat) { (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1); nfsrv_postopattr(nd, 0, &nva); } nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); } out: NFSEXITCODE2(error, nd); return (error); } /* * Common code for creating a symbolic link. */ static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, int pathlen) { u_int32_t *tl; nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); if (nd->nd_flag & ND_NFSV3) { nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, nvap, nd, p, 1, NULL); } if (vpp != NULL && nd->nd_repstat == 0) { NFSVOPUNLOCK(ndp->ni_vp); *vpp = ndp->ni_vp; } else vput(ndp->ni_vp); } if (dirp) { *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); vrele(dirp); } if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = newnfs_false; txdr_hyper(dirforp->na_filerev, tl); tl += 2; txdr_hyper(diraftp->na_filerev, tl); (void) nfsrv_putattrbit(nd, attrbitp); } NFSEXITCODE2(0, nd); } /* * nfs mkdir service */ int nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) { struct nfsvattr nva, dirfor, diraft; struct nameidata named; u_int32_t *tl; int error = 0, dirfor_ret = 1, diraft_ret = 1; vnode_t dirp = NULL; char *bufp; u_long *hashp; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) goto nfsmout; if (!nd->nd_repstat) { NFSVNO_ATTRINIT(&nva); if (nd->nd_flag & ND_NFSV3) { error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); if (error) goto nfsmout; } else { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); nva.na_mode = nfstov_mode(*tl++); } } if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); } else { vrele(dp); nfsvno_relpathbuf(&named); } if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { vrele(dirp); dirp = NULL; } if (nd->nd_repstat) { if (dirp != NULL) { dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); vrele(dirp); } if (nd->nd_flag & ND_NFSV3) nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } if (dirp != NULL) dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); /* * Call nfsrvd_mkdirsub() for the code common to V4 as well. */ nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp); if (nd->nd_flag & ND_NFSV3) { if (!nd->nd_repstat) { (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1); nfsrv_postopattr(nd, 0, &nva); } nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); } else if (!nd->nd_repstat) { (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0); nfsrv_fillattr(nd, &nva); } out: NFSEXITCODE2(0, nd); return (0); nfsmout: vrele(dp); nfsvno_relpathbuf(&named); NFSEXITCODE2(error, nd); return (error); } /* * Code common to mkdir for V2,3 and 4. */ static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp) { vnode_t vp; u_int32_t *tl; NFSVNO_SETATTRVAL(nvap, type, VDIR); nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, nd->nd_cred, p, exp); if (!nd->nd_repstat) { vp = ndp->ni_vp; nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); nd->nd_repstat = nfsvno_getfh(vp, fhp, p); if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1, NULL); if (vpp && !nd->nd_repstat) { NFSVOPUNLOCK(vp); *vpp = vp; } else { vput(vp); } } if (dirp) { *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); vrele(dirp); } if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = newnfs_false; txdr_hyper(dirforp->na_filerev, tl); tl += 2; txdr_hyper(diraftp->na_filerev, tl); (void) nfsrv_putattrbit(nd, attrbitp); } NFSEXITCODE2(0, nd); } /* * nfs commit service */ int nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { struct nfsvattr bfor, aft; u_int32_t *tl; int error = 0, for_ret = 1, aft_ret = 1, cnt; u_int64_t off; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); goto out; } /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */ if (vp->v_type != VREG) { if (nd->nd_flag & ND_NFSV3) error = NFSERR_NOTSUPP; else error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL; goto nfsmout; } NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); /* * XXX At this time VOP_FSYNC() does not accept offset and byte * count parameters, so these arguments are useless (someday maybe). */ off = fxdr_hyper(tl); tl += 2; cnt = fxdr_unsigned(int, *tl); if (nd->nd_flag & ND_NFSV3) for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL); nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); if (nd->nd_flag & ND_NFSV3) { aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL); nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); } vput(vp); if (!nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); *tl++ = txdr_unsigned(nfsboottime.tv_sec); *tl = txdr_unsigned(nfsboottime.tv_usec); } out: NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfs statfs service */ int nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { struct statfs *sf; u_int32_t *tl; int getret = 1; struct nfsvattr at; u_quad_t tval; struct thread *p = curthread; sf = NULL; if (nd->nd_repstat) { nfsrv_postopattr(nd, getret, &at); goto out; } sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); nd->nd_repstat = nfsvno_statfs(vp, sf); getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); vput(vp); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &at); if (nd->nd_repstat) goto out; if (nd->nd_flag & ND_NFSV2) { NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); *tl++ = txdr_unsigned(NFS_V2MAXDATA); *tl++ = txdr_unsigned(sf->f_bsize); *tl++ = txdr_unsigned(sf->f_blocks); *tl++ = txdr_unsigned(sf->f_bfree); *tl = txdr_unsigned(sf->f_bavail); } else { NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); tval = (u_quad_t)sf->f_blocks; tval *= (u_quad_t)sf->f_bsize; txdr_hyper(tval, tl); tl += 2; tval = (u_quad_t)sf->f_bfree; tval *= (u_quad_t)sf->f_bsize; txdr_hyper(tval, tl); tl += 2; tval = (u_quad_t)sf->f_bavail; tval *= (u_quad_t)sf->f_bsize; txdr_hyper(tval, tl); tl += 2; tval = (u_quad_t)sf->f_files; txdr_hyper(tval, tl); tl += 2; tval = (u_quad_t)sf->f_ffree; txdr_hyper(tval, tl); tl += 2; tval = (u_quad_t)sf->f_ffree; txdr_hyper(tval, tl); tl += 2; *tl = 0; } out: free(sf, M_STATFS); NFSEXITCODE2(0, nd); return (0); } /* * nfs fsinfo service */ int nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; struct nfsfsinfo fs; int getret = 1; struct nfsvattr at; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_postopattr(nd, getret, &at); goto out; } getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); nfsvno_getfs(&fs, isdgram); vput(vp); nfsrv_postopattr(nd, getret, &at); NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); *tl++ = txdr_unsigned(fs.fs_rtmax); *tl++ = txdr_unsigned(fs.fs_rtpref); *tl++ = txdr_unsigned(fs.fs_rtmult); *tl++ = txdr_unsigned(fs.fs_wtmax); *tl++ = txdr_unsigned(fs.fs_wtpref); *tl++ = txdr_unsigned(fs.fs_wtmult); *tl++ = txdr_unsigned(fs.fs_dtpref); txdr_hyper(fs.fs_maxfilesize, tl); tl += 2; txdr_nfsv3time(&fs.fs_timedelta, tl); tl += 2; *tl = txdr_unsigned(fs.fs_properties); out: NFSEXITCODE2(0, nd); return (0); } /* * nfs pathconf service */ int nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { struct nfsv3_pathconf *pc; int getret = 1; long linkmax, namemax, chownres, notrunc; struct nfsvattr at; struct thread *p = curthread; if (nd->nd_repstat) { nfsrv_postopattr(nd, getret, &at); goto out; } nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, nd->nd_cred, p); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, nd->nd_cred, p); if (!nd->nd_repstat) nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, &chownres, nd->nd_cred, p); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, nd->nd_cred, p); getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); vput(vp); nfsrv_postopattr(nd, getret, &at); if (!nd->nd_repstat) { NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); pc->pc_linkmax = txdr_unsigned(linkmax); pc->pc_namemax = txdr_unsigned(namemax); pc->pc_notrunc = txdr_unsigned(notrunc); pc->pc_chownrestricted = txdr_unsigned(chownres); /* * These should probably be supported by VOP_PATHCONF(), but * until msdosfs is exportable (why would you want to?), the * Unix defaults should be ok. */ pc->pc_caseinsensitive = newnfs_false; pc->pc_casepreserving = newnfs_true; } out: NFSEXITCODE2(0, nd); return (0); } /* * nfsv4 lock service */ int nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { u_int32_t *tl; int i; struct nfsstate *stp = NULL; struct nfslock *lop; struct nfslockconflict cf; int error = 0; u_short flags = NFSLCK_LOCK, lflags; u_int64_t offset, len; nfsv4stateid_t stateid; nfsquad_t clientid; struct thread *p = curthread; NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); i = fxdr_unsigned(int, *tl++); switch (i) { case NFSV4LOCKT_READW: flags |= NFSLCK_BLOCKING; case NFSV4LOCKT_READ: lflags = NFSLCK_READ; break; case NFSV4LOCKT_WRITEW: flags |= NFSLCK_BLOCKING; case NFSV4LOCKT_WRITE: lflags = NFSLCK_WRITE; break; default: nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } if (*tl++ == newnfs_true) flags |= NFSLCK_RECLAIM; offset = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); tl += 2; if (*tl == newnfs_true) flags |= NFSLCK_OPENTOLOCK; if (flags & NFSLCK_OPENTOLOCK) { NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); if (i <= 0 || i > NFSV4_OPAQUELIMIT) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } stp = malloc(sizeof (struct nfsstate) + i, M_NFSDSTATE, M_WAITOK); stp->ls_ownerlen = i; stp->ls_op = nd->nd_rp; stp->ls_seq = fxdr_unsigned(int, *tl++); stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); /* * For the special stateid of other all 0s and seqid == 1, set * the stateid to the current stateid, if it is set. */ if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && stp->ls_stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stp->ls_stateid = nd->nd_curstateid; stp->ls_stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); clientid.lval[0] = *tl++; clientid.lval[1] = *tl++; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK3 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); if (error) goto nfsmout; } else { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); stp = malloc(sizeof (struct nfsstate), M_NFSDSTATE, M_WAITOK); stp->ls_ownerlen = 0; stp->ls_op = nd->nd_rp; stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); /* * For the special stateid of other all 0s and seqid == 1, set * the stateid to the current stateid, if it is set. */ if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && stp->ls_stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stp->ls_stateid = nd->nd_curstateid; stp->ls_stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } stp->ls_seq = fxdr_unsigned(int, *tl); clientid.lval[0] = stp->ls_stateid.other[0]; clientid.lval[1] = stp->ls_stateid.other[1]; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK4 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } } lop = malloc(sizeof (struct nfslock), M_NFSDLOCK, M_WAITOK); lop->lo_first = offset; if (len == NFS64BITSSET) { lop->lo_end = NFS64BITSSET; } else { lop->lo_end = offset + len; if (lop->lo_end <= lop->lo_first) nd->nd_repstat = NFSERR_INVAL; } lop->lo_flags = lflags; stp->ls_flags = flags; stp->ls_uid = nd->nd_cred->cr_uid; /* * Do basic access checking. */ if (!nd->nd_repstat && vp->v_type != VREG) { if (vp->v_type == VDIR) nd->nd_repstat = NFSERR_ISDIR; else nd->nd_repstat = NFSERR_INVAL; } if (!nd->nd_repstat) { if (lflags & NFSLCK_WRITE) { nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); } else { nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); if (nd->nd_repstat) nd->nd_repstat = nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); } } /* * We call nfsrv_lockctrl() even if nd_repstat set, so that the * seqid# gets updated. nfsrv_lockctrl() will return the value * of nd_repstat, if it gets that far. */ nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, &stateid, exp, nd, p); if (lop) free(lop, M_NFSDLOCK); if (stp) free(stp, M_NFSDSTATE); if (!nd->nd_repstat) { /* For NFSv4.1, set the Current StateID. */ if ((nd->nd_flag & ND_NFSV41) != 0) { nd->nd_curstateid = stateid; nd->nd_flag |= ND_CURSTATEID; } NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); *tl++ = txdr_unsigned(stateid.seqid); NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); } else if (nd->nd_repstat == NFSERR_DENIED) { NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); txdr_hyper(cf.cl_first, tl); tl += 2; if (cf.cl_end == NFS64BITSSET) len = NFS64BITSSET; else len = cf.cl_end - cf.cl_first; txdr_hyper(len, tl); tl += 2; if (cf.cl_flags == NFSLCK_WRITE) *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); else *tl++ = txdr_unsigned(NFSV4LOCKT_READ); *tl++ = stateid.other[0]; *tl = stateid.other[1]; (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); } vput(vp); NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); if (stp) free(stp, M_NFSDSTATE); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 lock test service */ int nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { u_int32_t *tl; int i; struct nfsstate *stp = NULL; struct nfslock lo, *lop = &lo; struct nfslockconflict cf; int error = 0; nfsv4stateid_t stateid; nfsquad_t clientid; u_int64_t len; struct thread *p = curthread; NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); i = fxdr_unsigned(int, *(tl + 7)); if (i <= 0 || i > NFSV4_OPAQUELIMIT) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } stp = malloc(sizeof (struct nfsstate) + i, M_NFSDSTATE, M_WAITOK); stp->ls_ownerlen = i; stp->ls_op = NULL; stp->ls_flags = NFSLCK_TEST; stp->ls_uid = nd->nd_cred->cr_uid; i = fxdr_unsigned(int, *tl++); switch (i) { case NFSV4LOCKT_READW: stp->ls_flags |= NFSLCK_BLOCKING; case NFSV4LOCKT_READ: lo.lo_flags = NFSLCK_READ; break; case NFSV4LOCKT_WRITEW: stp->ls_flags |= NFSLCK_BLOCKING; case NFSV4LOCKT_WRITE: lo.lo_flags = NFSLCK_WRITE; break; default: nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } lo.lo_first = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); if (len == NFS64BITSSET) { lo.lo_end = NFS64BITSSET; } else { lo.lo_end = lo.lo_first + len; if (lo.lo_end <= lo.lo_first) nd->nd_repstat = NFSERR_INVAL; } tl += 2; clientid.lval[0] = *tl++; clientid.lval[1] = *tl; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK5 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); if (error) goto nfsmout; if (!nd->nd_repstat && vp->v_type != VREG) { if (vp->v_type == VDIR) nd->nd_repstat = NFSERR_ISDIR; else nd->nd_repstat = NFSERR_INVAL; } if (!nd->nd_repstat) nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, &stateid, exp, nd, p); if (nd->nd_repstat) { if (nd->nd_repstat == NFSERR_DENIED) { NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); txdr_hyper(cf.cl_first, tl); tl += 2; if (cf.cl_end == NFS64BITSSET) len = NFS64BITSSET; else len = cf.cl_end - cf.cl_first; txdr_hyper(len, tl); tl += 2; if (cf.cl_flags == NFSLCK_WRITE) *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); else *tl++ = txdr_unsigned(NFSV4LOCKT_READ); *tl++ = stp->ls_stateid.other[0]; *tl = stp->ls_stateid.other[1]; (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); } } vput(vp); if (stp) free(stp, M_NFSDSTATE); NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); if (stp) free(stp, M_NFSDSTATE); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 unlock service */ int nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { u_int32_t *tl; int i; struct nfsstate *stp; struct nfslock *lop; int error = 0; nfsv4stateid_t stateid; nfsquad_t clientid; u_int64_t len; struct thread *p = curthread; NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); stp = malloc(sizeof (struct nfsstate), M_NFSDSTATE, M_WAITOK); lop = malloc(sizeof (struct nfslock), M_NFSDLOCK, M_WAITOK); stp->ls_flags = NFSLCK_UNLOCK; lop->lo_flags = NFSLCK_UNLOCK; stp->ls_op = nd->nd_rp; i = fxdr_unsigned(int, *tl++); switch (i) { case NFSV4LOCKT_READW: stp->ls_flags |= NFSLCK_BLOCKING; case NFSV4LOCKT_READ: break; case NFSV4LOCKT_WRITEW: stp->ls_flags |= NFSLCK_BLOCKING; case NFSV4LOCKT_WRITE: break; default: nd->nd_repstat = NFSERR_BADXDR; free(stp, M_NFSDSTATE); free(lop, M_NFSDLOCK); goto nfsmout; } stp->ls_ownerlen = 0; stp->ls_uid = nd->nd_cred->cr_uid; stp->ls_seq = fxdr_unsigned(int, *tl++); stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); /* * For the special stateid of other all 0s and seqid == 1, set the * stateid to the current stateid, if it is set. */ if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && stp->ls_stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stp->ls_stateid = nd->nd_curstateid; stp->ls_stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; free(stp, M_NFSDSTATE); free(lop, M_NFSDLOCK); goto nfsmout; } } lop->lo_first = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); if (len == NFS64BITSSET) { lop->lo_end = NFS64BITSSET; } else { lop->lo_end = lop->lo_first + len; if (lop->lo_end <= lop->lo_first) nd->nd_repstat = NFSERR_INVAL; } clientid.lval[0] = stp->ls_stateid.other[0]; clientid.lval[1] = stp->ls_stateid.other[1]; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK6 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } if (!nd->nd_repstat && vp->v_type != VREG) { if (vp->v_type == VDIR) nd->nd_repstat = NFSERR_ISDIR; else nd->nd_repstat = NFSERR_INVAL; } /* * Call nfsrv_lockctrl() even if nd_repstat is set, so that the * seqid# gets incremented. nfsrv_lockctrl() will return the * value of nd_repstat, if it gets that far. */ nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, &stateid, exp, nd, p); if (stp) free(stp, M_NFSDSTATE); if (lop) free(lop, M_NFSDLOCK); if (!nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); *tl++ = txdr_unsigned(stateid.seqid); NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); } nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 open service */ int nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp) { u_int32_t *tl; int i, retext; struct nfsstate *stp = NULL; int error = 0, create, claim, exclusive_flag = 0, override; u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; int how = NFSCREATE_UNCHECKED; int32_t cverf[2], tverf[2] = { 0, 0 }; vnode_t vp = NULL, dirp = NULL; struct nfsvattr nva, dirfor, diraft, nva2; struct nameidata named; nfsv4stateid_t stateid, delegstateid; nfsattrbit_t attrbits; nfsquad_t clientid; char *bufp = NULL; u_long *hashp; NFSACL_T *aclp = NULL; struct thread *p = curthread; bool done_namei; __enum_uint8_decl(wdelegace) { USENONE, USEMODE, USENFSV4ACL } delegace; #ifdef NFS4_ACL_EXTATTR_NAME aclp = acl_alloc(M_WAITOK); aclp->acl_cnt = 0; #endif NFSZERO_ATTRBIT(&attrbits); done_namei = false; delegace = USEMODE; named.ni_cnd.cn_nameiop = 0; NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); i = fxdr_unsigned(int, *(tl + 5)); if (i <= 0 || i > NFSV4_OPAQUELIMIT) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } stp = malloc(sizeof (struct nfsstate) + i, M_NFSDSTATE, M_WAITOK); stp->ls_ownerlen = i; stp->ls_op = nd->nd_rp; stp->ls_flags = NFSLCK_OPEN; stp->ls_uid = nd->nd_cred->cr_uid; stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); i = fxdr_unsigned(int, *tl++); retext = 0; if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { retext = 1; /* For now, ignore these. */ i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); switch (i & NFSV4OPEN_WANTDELEGMASK) { case NFSV4OPEN_WANTANYDELEG: stp->ls_flags |= (NFSLCK_WANTRDELEG | NFSLCK_WANTWDELEG); i &= ~NFSV4OPEN_WANTDELEGMASK; break; case NFSV4OPEN_WANTREADDELEG: stp->ls_flags |= NFSLCK_WANTRDELEG; i &= ~NFSV4OPEN_WANTDELEGMASK; break; case NFSV4OPEN_WANTWRITEDELEG: stp->ls_flags |= NFSLCK_WANTWDELEG; i &= ~NFSV4OPEN_WANTDELEGMASK; break; case NFSV4OPEN_WANTNODELEG: stp->ls_flags |= NFSLCK_WANTNODELEG; i &= ~NFSV4OPEN_WANTDELEGMASK; break; case NFSV4OPEN_WANTCANCEL: printf("NFSv4: ignore Open WantCancel\n"); i &= ~NFSV4OPEN_WANTDELEGMASK; break; default: /* nd_repstat will be set to NFSERR_INVAL below. */ break; } } switch (i) { case NFSV4OPEN_ACCESSREAD: stp->ls_flags |= NFSLCK_READACCESS; break; case NFSV4OPEN_ACCESSWRITE: stp->ls_flags |= NFSLCK_WRITEACCESS; break; case NFSV4OPEN_ACCESSBOTH: stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); break; default: nd->nd_repstat = NFSERR_INVAL; } i = fxdr_unsigned(int, *tl++); switch (i) { case NFSV4OPEN_DENYNONE: break; case NFSV4OPEN_DENYREAD: stp->ls_flags |= NFSLCK_READDENY; break; case NFSV4OPEN_DENYWRITE: stp->ls_flags |= NFSLCK_WRITEDENY; break; case NFSV4OPEN_DENYBOTH: stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); break; default: nd->nd_repstat = NFSERR_INVAL; } clientid.lval[0] = *tl++; clientid.lval[1] = *tl; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK7 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); if (error) goto nfsmout; NFSVNO_ATTRINIT(&nva); NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); create = fxdr_unsigned(int, *tl); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); if (create == NFSV4OPEN_CREATE) { nva.na_type = VREG; nva.na_mode = 0; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); how = fxdr_unsigned(int, *tl); switch (how) { case NFSCREATE_UNCHECKED: case NFSCREATE_GUARDED: error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); if (error) goto nfsmout; /* * If the na_gid being set is the same as that of * the directory it is going in, clear it, since * that is what will be set by default. This allows * a user that isn't in that group to do the create. */ if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && nva.na_gid == dirfor.na_gid) NFSVNO_UNSET(&nva, gid); if (!nd->nd_repstat) nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); break; case NFSCREATE_EXCLUSIVE: NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); cverf[0] = *tl++; cverf[1] = *tl; if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0) nd->nd_repstat = NFSERR_INVAL; break; case NFSCREATE_EXCLUSIVE41: NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); cverf[0] = *tl++; cverf[1] = *tl; error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); if (error != 0) goto nfsmout; if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0 || NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) nd->nd_repstat = NFSERR_INVAL; /* * If the na_gid being set is the same as that of * the directory it is going in, clear it, since * that is what will be set by default. This allows * a user that isn't in that group to do the create. */ if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && nva.na_gid == dirfor.na_gid) NFSVNO_UNSET(&nva, gid); if (nd->nd_repstat == 0) nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); break; default: nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } } else if (create != NFSV4OPEN_NOCREATE) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } /* * Now, handle the claim, which usually includes looking up a * name in the directory referenced by dp. The exception is * NFSV4OPEN_CLAIMPREVIOUS. */ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); claim = fxdr_unsigned(int, *tl); if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim == NFSV4OPEN_CLAIMDELEGATECURFH) { NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); stp->ls_flags |= NFSLCK_DELEGCUR; } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) { stp->ls_flags |= NFSLCK_DELEGPREV; } if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && claim != NFSV4OPEN_CLAIMNULL) nd->nd_repstat = NFSERR_INVAL; if (nd->nd_repstat) { nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, NULL, nd, p, nd->nd_repstat); goto nfsmout; } if (create == NFSV4OPEN_CREATE) NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | LOCKLEAF | NOCACHE); else NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, LOCKLEAF); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) { vrele(dp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif free(stp, M_NFSDSTATE); nfsvno_relpathbuf(&named); NFSEXITCODE2(error, nd); return (error); } if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); } else { vrele(dp); nfsvno_relpathbuf(&named); } if (create == NFSV4OPEN_CREATE) { switch (how) { case NFSCREATE_UNCHECKED: if (nd->nd_repstat == 0 && named.ni_vp != NULL) { /* * Clear the setable attribute bits, except * for Size, if it is being truncated. */ NFSZERO_ATTRBIT(&attrbits); if (NFSVNO_ISSETSIZE(&nva)) NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); } break; case NFSCREATE_GUARDED: if (nd->nd_repstat == 0 && named.ni_vp != NULL) { nd->nd_repstat = EEXIST; done_namei = true; } break; case NFSCREATE_EXCLUSIVE: if (nd->nd_repstat == 0 && named.ni_vp == NULL) nva.na_mode = 0; /* FALLTHROUGH */ case NFSCREATE_EXCLUSIVE41: if (nd->nd_repstat == 0 && named.ni_vp != NULL) { nd->nd_repstat = nfsvno_getattr(named.ni_vp, &nva2, nd, p, 1, NULL); if (nd->nd_repstat == 0) { tverf[0] = nva2.na_atime.tv_sec; tverf[1] = nva2.na_atime.tv_nsec; if (cverf[0] != tverf[0] || cverf[1] != tverf[1]) nd->nd_repstat = EEXIST; } if (nd->nd_repstat != 0) done_namei = true; } exclusive_flag = 1; break; } } nfsvno_open(nd, &named, clientid, &stateid, stp, &exclusive_flag, &nva, cverf, create, aclp, &attrbits, nd->nd_cred, done_namei, exp, &vp); } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH || claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) { if (claim == NFSV4OPEN_CLAIMPREVIOUS) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); i = fxdr_unsigned(int, *tl); switch (i) { case NFSV4OPEN_DELEGATEREAD: stp->ls_flags |= NFSLCK_DELEGREAD; break; case NFSV4OPEN_DELEGATEWRITE: stp->ls_flags |= NFSLCK_DELEGWRITE; case NFSV4OPEN_DELEGATENONE: break; default: nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } stp->ls_flags |= NFSLCK_RECLAIM; } else { if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) nd->nd_repstat = NFSERR_INVAL; } vp = dp; NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); if (!VN_IS_DOOMED(vp)) nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp, nd, p, nd->nd_repstat); else nd->nd_repstat = NFSERR_PERM; } else { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } /* * Do basic access checking. */ if (!nd->nd_repstat && vp->v_type != VREG) { /* * The IETF working group decided that this is the correct * error return for all non-regular files. */ nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; } /* * If the Open is being done for a file that already exists, apply * normal permission checking including for the file owner, if * vfs.nfsd.v4openaccess is set. * Previously, the owner was always allowed to open the file to * be consistent with the NFS tradition of always allowing the * owner of the file to write to the file regardless of permissions. * It now appears that the Linux client expects the owner * permissions to be checked for opens that are not creating the * file. I believe the correct approach is to use the Access * operation's results to be consistent with NFSv3, but that is * not what the current Linux client appears to be doing. * Since both the Linux and OpenSolaris NFSv4 servers do this check, * I have enabled it by default. Since Linux does not apply this * check for claim_delegate_cur, this code does the same. * If this semantic change causes a problem, it can be disabled by * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the * previous semantics. */ if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE && (stp->ls_flags & NFSLCK_DELEGCUR) == 0) override = NFSACCCHK_NOOVERRIDE; else override = NFSACCCHK_ALLOWOWNER; if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, override, NFSACCCHK_VPISLOCKED, NULL); if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, override, NFSACCCHK_VPISLOCKED, NULL); if (nd->nd_repstat) nd->nd_repstat = nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, override, NFSACCCHK_VPISLOCKED, NULL); } if (!nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); if (nd->nd_repstat == 0 && aclp != NULL && nfsrv_issuedelegs != 0 && (dp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) { if (aclp->acl_cnt == 0 && create == NFSV4OPEN_NOCREATE) { int retacl; /* We do not yet have an ACL, so try and get one. */ retacl = VOP_GETACL(vp, ACL_TYPE_NFS4, aclp, nd->nd_cred, p); if (retacl != 0 && retacl != ENOATTR && retacl != EOPNOTSUPP && retacl != EINVAL) delegace = USENONE; else if (retacl == 0 && aclp->acl_cnt > 0) delegace = USENFSV4ACL; } else if (aclp->acl_cnt > 0 && create == NFSV4OPEN_CREATE) { delegace = USENFSV4ACL; } } /* * Do the open locking/delegation stuff. */ if (!nd->nd_repstat) nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, &delegstateid, &rflags, exp, p, nva.na_filerev); /* * vp must be unlocked before the call to nfsvno_getattr(dirp,...) * below, to avoid a deadlock with the lookup in nfsvno_namei() above. * (ie: Leave the NFSVOPUNLOCK() about here.) */ if (vp) NFSVOPUNLOCK(vp); if (stp) free(stp, M_NFSDSTATE); if (!nd->nd_repstat && dirp) nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); if (!nd->nd_repstat) { /* For NFSv4.1, set the Current StateID. */ if ((nd->nd_flag & ND_NFSV41) != 0) { nd->nd_curstateid = stateid; nd->nd_flag |= ND_CURSTATEID; } NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(stateid.seqid); NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); if (claim == NFSV4OPEN_CLAIMPREVIOUS) { *tl++ = newnfs_true; *tl++ = 0; *tl++ = 0; *tl++ = 0; *tl++ = 0; } else { *tl++ = newnfs_false; /* Since dirp is not locked */ txdr_hyper(dirfor.na_filerev, tl); tl += 2; txdr_hyper(diraft.na_filerev, tl); tl += 2; } *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); (void) nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); if (rflags & NFSV4OPEN_READDELEGATE) *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); else if (rflags & NFSV4OPEN_WRITEDELEGATE) *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); else if (retext != 0) { *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); *tl = newnfs_false; } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); *tl = newnfs_false; } else if ((rflags & NFSV4OPEN_WDNOTSUPPDOWNGRADE) != 0) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPDOWNGRADE); } else if ((rflags & NFSV4OPEN_WDNOTSUPPUPGRADE) != 0) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPUPGRADE); } else { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); } } else *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); *tl++ = txdr_unsigned(delegstateid.seqid); NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); if (rflags & NFSV4OPEN_RECALL) *tl = newnfs_true; else *tl = newnfs_false; if (rflags & NFSV4OPEN_WRITEDELEGATE) { NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); txdr_hyper(nva.na_size, tl); } /* Set up the write delegation ACE. */ NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); if (delegace == USENFSV4ACL) { int j; for (j = 0; j < aclp->acl_cnt; j++) { if (aclp->acl_entry[j].ae_tag == ACL_USER_OBJ || aclp->acl_entry[j].ae_entry_type != ACL_ENTRY_TYPE_ALLOW) break; } if (j < aclp->acl_cnt && aclp->acl_entry[j].ae_tag == ACL_USER_OBJ && aclp->acl_entry[j].ae_entry_type == ACL_ENTRY_TYPE_ALLOW) { /* Use this ACE. */ *tl++ = txdr_unsigned( NFSV4ACE_ALLOWEDTYPE); *tl++ = txdr_unsigned(0x0); *tl = txdr_unsigned( nfs_aceperm( aclp->acl_entry[j].ae_perm)); (void)nfsm_strtom(nd, "OWNER@", 6); } else delegace = USENONE; } if (delegace == USENONE) { /* Don't allow anything. */ *tl++ = 0x0; *tl++ = 0x0; *tl = 0x0; NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = 0; } else if (delegace == USEMODE) { /* Build from mode. */ *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); *tl++ = txdr_unsigned(0x0); acemask = NFSV4ACE_ALLFILESMASK; if (nva.na_mode & S_IRUSR) acemask |= NFSV4ACE_READMASK; if (nva.na_mode & S_IWUSR) acemask |= NFSV4ACE_WRITEMASK; if (nva.na_mode & S_IXUSR) acemask |= NFSV4ACE_EXECUTEMASK; *tl = txdr_unsigned(acemask); (void)nfsm_strtom(nd, "OWNER@", 6); } } *vpp = vp; } else if (vp) { vrele(vp); } if (dirp) vrele(dirp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif NFSEXITCODE2(0, nd); return (0); nfsmout: vrele(dp); #ifdef NFS4_ACL_EXTATTR_NAME acl_free(aclp); #endif if (stp) free(stp, M_NFSDSTATE); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 close service */ int nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; struct nfsstate st, *stp = &st; int error = 0, writeacc; nfsv4stateid_t stateid; nfsquad_t clientid; struct nfsvattr na; struct thread *p = curthread; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); stp->ls_ownerlen = 0; stp->ls_op = nd->nd_rp; stp->ls_uid = nd->nd_cred->cr_uid; stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, NFSX_STATEIDOTHER); /* * For the special stateid of other all 0s and seqid == 1, set the * stateid to the current stateid, if it is set. */ if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && stp->ls_stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) stp->ls_stateid = nd->nd_curstateid; else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } stp->ls_flags = NFSLCK_CLOSE; clientid.lval[0] = stp->ls_stateid.other[0]; clientid.lval[1] = stp->ls_stateid.other[1]; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK8 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, &writeacc); /* For pNFS, update the attributes. */ if (writeacc != 0 || nfsrv_pnfsatime != 0) nfsrv_updatemdsattr(vp, &na, p); vput(vp); if (!nd->nd_repstat) { /* * If the stateid that has been closed is the current stateid, * unset it. */ if ((nd->nd_flag & ND_CURSTATEID) != 0 && stateid.other[0] == nd->nd_curstateid.other[0] && stateid.other[1] == nd->nd_curstateid.other[1] && stateid.other[2] == nd->nd_curstateid.other[2]) nd->nd_flag &= ~ND_CURSTATEID; NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); *tl++ = txdr_unsigned(stateid.seqid); NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); } NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 delegpurge service */ int nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; int error = 0; nfsquad_t clientid; struct thread *p = curthread; if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); clientid.lval[0] = *tl++; clientid.lval[1] = *tl; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK9 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 delegreturn service */ int nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; int error = 0, writeacc; nfsv4stateid_t stateid; nfsquad_t clientid; struct nfsvattr na; struct thread *p = curthread; NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); clientid.lval[0] = stateid.other[0]; clientid.lval[1] = stateid.other[1]; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK10 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); /* For pNFS, update the attributes. */ if (writeacc != 0 || nfsrv_pnfsatime != 0) nfsrv_updatemdsattr(vp, &na, p); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 get file handle service */ int nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { fhandle_t fh; struct thread *p = curthread; int siz; short irflag; nd->nd_repstat = nfsvno_getfh(vp, &fh, p); irflag = vn_irflag_read(vp); vput(vp); if (nd->nd_repstat == 0) { siz = 0; if ((irflag & VIRF_NAMEDDIR) != 0) siz = NFSX_FHMAX + NFSX_V4NAMEDDIRFH; else if ((irflag & VIRF_NAMEDATTR) != 0) siz = NFSX_FHMAX + NFSX_V4NAMEDATTRFH; (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, siz, 0); } NFSEXITCODE2(0, nd); return (0); } /* * nfsv4 open confirm service */ int nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; struct nfsstate st, *stp = &st; int error = 0; nfsv4stateid_t stateid; nfsquad_t clientid; struct thread *p = curthread; if ((nd->nd_flag & ND_NFSV41) != 0) { nd->nd_repstat = NFSERR_NOTSUPP; goto nfsmout; } NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); stp->ls_ownerlen = 0; stp->ls_op = nd->nd_rp; stp->ls_uid = nd->nd_cred->cr_uid; stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); stp->ls_flags = NFSLCK_CONFIRM; clientid.lval[0] = stp->ls_stateid.other[0]; clientid.lval[1] = stp->ls_stateid.other[1]; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK11 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, NULL); if (!nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); *tl++ = txdr_unsigned(stateid.seqid); NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); } nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 open downgrade service */ int nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; int i; struct nfsstate st, *stp = &st; int error = 0; nfsv4stateid_t stateid; nfsquad_t clientid; struct thread *p = curthread; /* opendowngrade can only work on a file object.*/ if (vp->v_type != VREG) { error = NFSERR_INVAL; goto nfsmout; } NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); stp->ls_ownerlen = 0; stp->ls_op = nd->nd_rp; stp->ls_uid = nd->nd_cred->cr_uid; stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); /* * For the special stateid of other all 0s and seqid == 1, set the * stateid to the current stateid, if it is set. */ if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && stp->ls_stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) stp->ls_stateid = nd->nd_curstateid; else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); i = fxdr_unsigned(int, *tl++); if ((nd->nd_flag & ND_NFSV41) != 0) i &= ~NFSV4OPEN_WANTDELEGMASK; switch (i) { case NFSV4OPEN_ACCESSREAD: stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); break; case NFSV4OPEN_ACCESSWRITE: stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); break; case NFSV4OPEN_ACCESSBOTH: stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); break; default: nd->nd_repstat = NFSERR_INVAL; } i = fxdr_unsigned(int, *tl); switch (i) { case NFSV4OPEN_DENYNONE: break; case NFSV4OPEN_DENYREAD: stp->ls_flags |= NFSLCK_READDENY; break; case NFSV4OPEN_DENYWRITE: stp->ls_flags |= NFSLCK_WRITEDENY; break; case NFSV4OPEN_DENYBOTH: stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); break; default: nd->nd_repstat = NFSERR_INVAL; } clientid.lval[0] = stp->ls_stateid.other[0]; clientid.lval[1] = stp->ls_stateid.other[1]; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK12 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } if (!nd->nd_repstat) nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, NULL); if (!nd->nd_repstat) { /* For NFSv4.1, set the Current StateID. */ if ((nd->nd_flag & ND_NFSV41) != 0) { nd->nd_curstateid = stateid; nd->nd_flag |= ND_CURSTATEID; } NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); *tl++ = txdr_unsigned(stateid.seqid); NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); } nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 renew lease service */ int nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; int error = 0; nfsquad_t clientid; struct thread *p = curthread; if ((nd->nd_flag & ND_NFSV41) != 0) { nd->nd_repstat = NFSERR_NOTSUPP; goto nfsmout; } if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); clientid.lval[0] = *tl++; clientid.lval[1] = *tl; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK13 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 security info service */ int nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, vnode_t dp, struct nfsexstuff *exp) { u_int32_t *tl; int len; struct nameidata named; vnode_t dirp = NULL, vp; struct nfsrvfh fh; struct nfsexstuff retnes; u_int32_t *sizp; int error = 0, i; uint64_t savflag; char *bufp; u_long *hashp; struct thread *p = curthread; /* * All this just to get the export flags for the name. */ NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, LOCKLEAF); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) { vput(dp); nfsvno_relpathbuf(&named); goto out; } if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); } else { vput(dp); nfsvno_relpathbuf(&named); } if (dirp) vrele(dirp); if (nd->nd_repstat) goto out; nfsvno_relpathbuf(&named); fh.nfsrvfh_len = NFSX_MYFH; vp = named.ni_vp; nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); vput(vp); savflag = nd->nd_flag; if (!nd->nd_repstat) { /* * Pretend the next op is Secinfo, so that no wrongsec * test will be done. */ nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, NFSV4OP_SECINFO); if (vp) vput(vp); } nd->nd_flag = savflag; if (nd->nd_repstat) goto out; /* * Finally have the export flags for name, so we can create * the security info. */ len = 0; NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); /* If nes_numsecflavor == 0, all are allowed. */ if (retnes.nes_numsecflavor == 0) { NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(RPCAUTH_UNIX); *tl = txdr_unsigned(RPCAUTH_GSS); nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); *tl = txdr_unsigned(RPCAUTH_GSS); nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); *tl = txdr_unsigned(RPCAUTH_GSS); nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); len = 4; } for (i = 0; i < retnes.nes_numsecflavor; i++) { if (retnes.nes_secflavors[i] == AUTH_SYS) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(RPCAUTH_UNIX); len++; } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl++ = txdr_unsigned(RPCAUTH_GSS); (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); len++; } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl++ = txdr_unsigned(RPCAUTH_GSS); (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); len++; } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl++ = txdr_unsigned(RPCAUTH_GSS); (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); len++; } } *sizp = txdr_unsigned(len); out: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 security info no name service */ int nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram, vnode_t dp, struct nfsexstuff *exp) { uint32_t *tl, *sizp; struct nameidata named; vnode_t dirp = NULL, vp; struct nfsrvfh fh; struct nfsexstuff retnes; int error = 0, fhstyle, i, len; uint64_t savflag; char *bufp; u_long *hashp; struct thread *p = curthread; NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); fhstyle = fxdr_unsigned(int, *tl); switch (fhstyle) { case NFSSECINFONONAME_PARENT: if (dp->v_type != VDIR) { vput(dp); nd->nd_repstat = NFSERR_NOTDIR; goto nfsmout; } NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, LOCKLEAF); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error != 0) { vput(dp); nfsvno_relpathbuf(&named); goto nfsmout; } if (nd->nd_repstat == 0) nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); else vput(dp); if (dirp != NULL) vrele(dirp); nfsvno_relpathbuf(&named); vp = named.ni_vp; break; case NFSSECINFONONAME_CURFH: vp = dp; break; default: nd->nd_repstat = NFSERR_INVAL; vput(dp); } if (nd->nd_repstat != 0) goto nfsmout; fh.nfsrvfh_len = NFSX_MYFH; nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); vput(vp); savflag = nd->nd_flag; if (nd->nd_repstat == 0) { /* * Pretend the next op is Secinfo, so that no wrongsec * test will be done. */ nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, NFSV4OP_SECINFO); if (vp != NULL) vput(vp); } nd->nd_flag = savflag; if (nd->nd_repstat != 0) goto nfsmout; /* * Finally have the export flags for fh/parent, so we can create * the security info. */ len = 0; NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED); /* If nes_numsecflavor == 0, all are allowed. */ if (retnes.nes_numsecflavor == 0) { NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(RPCAUTH_UNIX); *tl = txdr_unsigned(RPCAUTH_GSS); nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); *tl = txdr_unsigned(RPCAUTH_GSS); nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); *tl = txdr_unsigned(RPCAUTH_GSS); nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); len = 4; } for (i = 0; i < retnes.nes_numsecflavor; i++) { if (retnes.nes_secflavors[i] == AUTH_SYS) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(RPCAUTH_UNIX); len++; } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(RPCAUTH_GSS); nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); len++; } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(RPCAUTH_GSS); nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); len++; } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(RPCAUTH_GSS); nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, nfsgss_mechlist[KERBV_MECH].len); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(GSS_KERBV_QOP); *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); len++; } } *sizp = txdr_unsigned(len); nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 set client id service */ int nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; int i; int error = 0, idlen; struct nfsclient *clp = NULL; #ifdef INET struct sockaddr_in *rin; #endif #ifdef INET6 struct sockaddr_in6 *rin6; #endif #if defined(INET) || defined(INET6) u_char *ucp, *ucp2; #endif u_char *verf, *addrbuf; nfsquad_t clientid, confirm; struct thread *p = curthread; if ((nd->nd_flag & ND_NFSV41) != 0) { nd->nd_repstat = NFSERR_NOTSUPP; goto nfsmout; } if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto out; NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); verf = (u_char *)tl; tl += (NFSX_VERF / NFSX_UNSIGNED); i = fxdr_unsigned(int, *tl); if (i > NFSV4_OPAQUELIMIT || i <= 0) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } idlen = i; if (nd->nd_flag & ND_GSS) i += nd->nd_princlen; clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | M_ZERO); clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); /* Allocated large enough for an AF_INET or AF_INET6 socket. */ clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, M_WAITOK | M_ZERO); clp->lc_req.nr_cred = NULL; NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); clp->lc_idlen = idlen; error = nfsrv_mtostr(nd, clp->lc_id, idlen); if (error) goto nfsmout; if (nd->nd_flag & ND_GSS) { clp->lc_flags = LCL_GSS; if (nd->nd_flag & ND_GSSINTEGRITY) clp->lc_flags |= LCL_GSSINTEGRITY; else if (nd->nd_flag & ND_GSSPRIVACY) clp->lc_flags |= LCL_GSSPRIVACY; } else { clp->lc_flags = 0; } if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { clp->lc_flags |= LCL_NAME; clp->lc_namelen = nd->nd_princlen; clp->lc_name = &clp->lc_id[idlen]; NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); } else { clp->lc_uid = nd->nd_cred->cr_uid; clp->lc_gid = nd->nd_cred->cr_gid; } /* If the client is using TLS, do so for the callback connection. */ if (nd->nd_flag & ND_TLS) clp->lc_flags |= LCL_TLSCB; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); clp->lc_program = fxdr_unsigned(u_int32_t, *tl); error = nfsrv_getclientipaddr(nd, clp); if (error) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); /* * nfsrv_setclient() does the actual work of adding it to the * client list. If there is no error, the structure has been * linked into the client list and clp should no longer be used * here. When an error is returned, it has not been linked in, * so it should be free'd. */ nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); if (nd->nd_repstat == NFSERR_CLIDINUSE) { /* * 8 is the maximum length of the port# string. */ addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK); switch (clp->lc_req.nr_nam->sa_family) { #ifdef INET case AF_INET: if (clp->lc_flags & LCL_TCPCALLBACK) (void) nfsm_strtom(nd, "tcp", 3); else (void) nfsm_strtom(nd, "udp", 3); rin = (struct sockaddr_in *)clp->lc_req.nr_nam; ucp = (u_char *)&rin->sin_addr.s_addr; ucp2 = (u_char *)&rin->sin_port; sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, ucp2[0] & 0xff, ucp2[1] & 0xff); break; #endif #ifdef INET6 case AF_INET6: if (clp->lc_flags & LCL_TCPCALLBACK) (void) nfsm_strtom(nd, "tcp6", 4); else (void) nfsm_strtom(nd, "udp6", 4); rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf, INET6_ADDRSTRLEN); if (ucp != NULL) i = strlen(ucp); else i = 0; ucp2 = (u_char *)&rin6->sin6_port; sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff, ucp2[1] & 0xff); break; #endif } (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); free(addrbuf, M_TEMP); } if (clp) { free(clp->lc_req.nr_nam, M_SONAME); NFSFREEMUTEX(&clp->lc_req.nr_mtx); free(clp->lc_stateid, M_NFSDCLIENT); free(clp, M_NFSDCLIENT); } if (!nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); *tl++ = clientid.lval[0]; *tl++ = clientid.lval[1]; *tl++ = confirm.lval[0]; *tl = confirm.lval[1]; } out: NFSEXITCODE2(0, nd); return (0); nfsmout: if (clp) { free(clp->lc_req.nr_nam, M_SONAME); NFSFREEMUTEX(&clp->lc_req.nr_mtx); free(clp->lc_stateid, M_NFSDCLIENT); free(clp, M_NFSDCLIENT); } NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 set client id confirm service */ int nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; int error = 0; nfsquad_t clientid, confirm; struct thread *p = curthread; if ((nd->nd_flag & ND_NFSV41) != 0) { nd->nd_repstat = NFSERR_NOTSUPP; goto nfsmout; } if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); clientid.lval[0] = *tl++; clientid.lval[1] = *tl++; confirm.lval[0] = *tl++; confirm.lval[1] = *tl; /* * nfsrv_getclient() searches the client list for a match and * returns the appropriate NFSERR status. */ nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), NULL, NULL, confirm, 0, nd, p); nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 verify service */ int nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { int error = 0, ret, fhsize = NFSX_MYFH; struct nfsvattr nva; struct statfs *sf; struct nfsfsinfo fs; fhandle_t fh; struct thread *p = curthread; sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_statfs(vp, sf); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 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, NULL, p, nd->nd_cred); if (!error) { if (nd->nd_procnum == NFSV4OP_NVERIFY) { if (ret == 0) nd->nd_repstat = NFSERR_SAME; else if (ret != NFSERR_NOTSAME) nd->nd_repstat = ret; } else if (ret) nd->nd_repstat = ret; } } vput(vp); free(sf, M_STATFS); NFSEXITCODE2(error, nd); return (error); } /* * nfs openattr rpc */ int nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, struct vnode *dp, struct vnode **vpp, __unused fhandle_t *fhp, __unused struct nfsexstuff *exp) { uint32_t *tl; struct componentname cn; int error = 0; NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN | NOFOLLOW | LOCKLEAF); cn.cn_nameptr = "."; cn.cn_namelen = 1; cn.cn_lkflags = LK_SHARED; NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); if (*tl == newnfs_true) cn.cn_flags |= CREATENAMED; nd->nd_repstat = vn_lock(dp, LK_SHARED); if (nd->nd_repstat != 0) goto nfsmout; if ((dp->v_mount->mnt_flag & MNT_NAMEDATTR) == 0) nd->nd_repstat = NFSERR_NOTSUPP; if (nd->nd_repstat == 0 && (vn_irflag_read(dp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0) nd->nd_repstat = NFSERR_WRONGTYPE; if (nd->nd_repstat == 0) { nd->nd_repstat = VOP_LOOKUP(dp, vpp, &cn); if (nd->nd_repstat == ENOATTR) nd->nd_repstat = NFSERR_NOENT; } if (nd->nd_repstat == 0) NFSVOPUNLOCK(*vpp); vput(dp); NFSEXITCODE2(0, nd); return (0); nfsmout: vrele(dp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 release lock owner service */ int nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { u_int32_t *tl; struct nfsstate *stp = NULL; int error = 0, len; nfsquad_t clientid; struct thread *p = curthread; if ((nd->nd_flag & ND_NFSV41) != 0) { nd->nd_repstat = NFSERR_NOTSUPP; goto nfsmout; } if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); len = fxdr_unsigned(int, *(tl + 2)); if (len <= 0 || len > NFSV4_OPAQUELIMIT) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } stp = malloc(sizeof (struct nfsstate) + len, M_NFSDSTATE, M_WAITOK); stp->ls_ownerlen = len; stp->ls_op = NULL; stp->ls_flags = NFSLCK_RELEASE; stp->ls_uid = nd->nd_cred->cr_uid; clientid.lval[0] = *tl++; clientid.lval[1] = *tl; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK14 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } error = nfsrv_mtostr(nd, stp->ls_owner, len); if (error) goto nfsmout; nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); free(stp, M_NFSDSTATE); NFSEXITCODE2(0, nd); return (0); nfsmout: if (stp) free(stp, M_NFSDSTATE); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 exchange_id service */ int nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; int error = 0, i, idlen; struct nfsclient *clp = NULL; nfsquad_t clientid, confirm; uint8_t *verf; uint32_t sp4type, v41flags; struct timespec verstime; nfsopbit_t mustops, allowops; #ifdef INET struct sockaddr_in *sin, *rin; #endif #ifdef INET6 struct sockaddr_in6 *sin6, *rin6; #endif struct thread *p = curthread; char *s; if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); verf = (uint8_t *)tl; tl += (NFSX_VERF / NFSX_UNSIGNED); i = fxdr_unsigned(int, *tl); if (i > NFSV4_OPAQUELIMIT || i <= 0) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } idlen = i; if (nd->nd_flag & ND_GSS) i += nd->nd_princlen; clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | M_ZERO); clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); /* Allocated large enough for an AF_INET or AF_INET6 socket. */ clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, M_WAITOK | M_ZERO); switch (nd->nd_nam->sa_family) { #ifdef INET case AF_INET: rin = (struct sockaddr_in *)clp->lc_req.nr_nam; sin = (struct sockaddr_in *)nd->nd_nam; rin->sin_family = AF_INET; rin->sin_len = sizeof(struct sockaddr_in); rin->sin_port = 0; rin->sin_addr.s_addr = sin->sin_addr.s_addr; break; #endif #ifdef INET6 case AF_INET6: rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; sin6 = (struct sockaddr_in6 *)nd->nd_nam; rin6->sin6_family = AF_INET6; rin6->sin6_len = sizeof(struct sockaddr_in6); rin6->sin6_port = 0; rin6->sin6_addr = sin6->sin6_addr; break; #endif } clp->lc_req.nr_cred = NULL; NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); clp->lc_idlen = idlen; error = nfsrv_mtostr(nd, clp->lc_id, idlen); if (error != 0) goto nfsmout; if ((nd->nd_flag & ND_GSS) != 0) { clp->lc_flags = LCL_GSS | LCL_NFSV41; if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) clp->lc_flags |= LCL_GSSINTEGRITY; else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) clp->lc_flags |= LCL_GSSPRIVACY; } else clp->lc_flags = LCL_NFSV41; if ((nd->nd_flag & ND_NFSV42) != 0) clp->lc_flags |= LCL_NFSV42; if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { clp->lc_flags |= LCL_NAME; clp->lc_namelen = nd->nd_princlen; clp->lc_name = &clp->lc_id[idlen]; NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); } else { clp->lc_uid = nd->nd_cred->cr_uid; clp->lc_gid = nd->nd_cred->cr_gid; } NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); v41flags = fxdr_unsigned(uint32_t, *tl++); if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { nd->nd_repstat = NFSERR_INVAL; goto nfsmout; } if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) confirm.lval[1] = 1; else confirm.lval[1] = 0; if (nfsrv_devidcnt == 0) v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; else v41flags = NFSV4EXCH_USEPNFSMDS; sp4type = fxdr_unsigned(uint32_t, *tl); if (sp4type == NFSV4EXCH_SP4MACHCRED) { if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 || nd->nd_princlen == 0) nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); if (nd->nd_repstat == 0) nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL); if (nd->nd_repstat == 0) nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL); if (nd->nd_repstat != 0) goto nfsmout; NFSOPBIT_CLRNOTMUST(&mustops); NFSSET_OPBIT(&clp->lc_mustops, &mustops); NFSOPBIT_CLRNOTALLOWED(&allowops); NFSSET_OPBIT(&clp->lc_allowops, &allowops); clp->lc_flags |= LCL_MACHCRED; } else if (sp4type != NFSV4EXCH_SP4NONE) { nd->nd_repstat = NFSERR_NOTSUPP; goto nfsmout; } /* * nfsrv_setclient() does the actual work of adding it to the * client list. If there is no error, the structure has been * linked into the client list and clp should no longer be used * here. When an error is returned, it has not been linked in, * so it should be free'd. */ nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); if (clp != NULL) { free(clp->lc_req.nr_nam, M_SONAME); NFSFREEMUTEX(&clp->lc_req.nr_mtx); free(clp->lc_stateid, M_NFSDCLIENT); free(clp, M_NFSDCLIENT); } if (nd->nd_repstat == 0) { if (confirm.lval[1] != 0) v41flags |= NFSV4EXCH_CONFIRMEDR; NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); *tl++ = clientid.lval[0]; /* ClientID */ *tl++ = clientid.lval[1]; *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ *tl++ = txdr_unsigned(v41flags); /* Exch flags */ *tl = txdr_unsigned(sp4type); /* No SSV */ if (sp4type == NFSV4EXCH_SP4MACHCRED) { nfsrv_putopbit(nd, &mustops); nfsrv_putopbit(nd, &allowops); } NFSM_BUILD(tl, uint32_t *, NFSX_HYPER); txdr_hyper(nfsrv_owner_minor, tl); /* Owner Minor */ if (nfsrv_owner_major[0] != 0) s = nfsrv_owner_major; else s = nd->nd_cred->cr_prison->pr_hostuuid; nfsm_strtom(nd, s, strlen(s)); /* Owner Major */ if (nfsrv_scope[0] != 0) s = nfsrv_scope; else s = nd->nd_cred->cr_prison->pr_hostuuid; nfsm_strtom(nd, s, strlen(s) ); /* Scope */ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(1); (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); (void)nfsm_strtom(nd, version, strlen(version)); NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ verstime.tv_nsec = 0; txdr_nfsv4time(&verstime, tl); } NFSEXITCODE2(0, nd); return (0); nfsmout: if (clp != NULL) { free(clp->lc_req.nr_nam, M_SONAME); NFSFREEMUTEX(&clp->lc_req.nr_mtx); free(clp->lc_stateid, M_NFSDCLIENT); free(clp, M_NFSDCLIENT); } NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 create session service */ int nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; int error = 0; nfsquad_t clientid, confirm; struct nfsdsession *sep = NULL; uint32_t rdmacnt; struct thread *p = curthread; static bool do_printf = true; if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), M_NFSDSESSION, M_WAITOK | M_ZERO); sep->sess_refcnt = 1; mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); clientid.lval[0] = *tl++; clientid.lval[1] = *tl++; confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); /* Persistent sessions and RDMA are not supported. */ sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; /* Fore channel attributes. */ NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); tl++; /* Header pad always 0. */ sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; if (do_printf) printf("Consider increasing kern.ipc.maxsockbuf\n"); do_printf = false; } sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; if (do_printf) printf("Consider increasing kern.ipc.maxsockbuf\n"); do_printf = false; } sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); if (sep->sess_maxslots > NFSV4_SLOTS) sep->sess_maxslots = NFSV4_SLOTS; rdmacnt = fxdr_unsigned(uint32_t, *tl); if (rdmacnt > 1) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } else if (rdmacnt == 1) NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); /* Back channel attributes. */ NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); tl++; /* Header pad always 0. */ sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); rdmacnt = fxdr_unsigned(uint32_t, *tl); if (rdmacnt > 1) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } else if (rdmacnt == 1) NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); /* * nfsrv_getclient() searches the client list for a match and * returns the appropriate NFSERR status. */ nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, NULL, sep, confirm, sep->sess_cbprogram, nd, p); if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ *tl++ = txdr_unsigned(sep->sess_crflags); /* Fore channel attributes. */ *tl++ = 0; *tl++ = txdr_unsigned(sep->sess_maxreq); *tl++ = txdr_unsigned(sep->sess_maxresp); *tl++ = txdr_unsigned(sep->sess_maxrespcached); *tl++ = txdr_unsigned(sep->sess_maxops); *tl++ = txdr_unsigned(sep->sess_maxslots); *tl++ = txdr_unsigned(1); *tl++ = txdr_unsigned(0); /* No RDMA. */ /* Back channel attributes. */ *tl++ = 0; *tl++ = txdr_unsigned(sep->sess_cbmaxreq); *tl++ = txdr_unsigned(sep->sess_cbmaxresp); *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); *tl++ = txdr_unsigned(sep->sess_cbmaxops); *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); *tl++ = txdr_unsigned(1); *tl = txdr_unsigned(0); /* No RDMA. */ } nfsmout: if (nd->nd_repstat != 0 && sep != NULL) free(sep, M_NFSDSESSION); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 sequence service */ int nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; int cache_this, error = 0; struct thread *p = curthread; if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); sequenceid = fxdr_unsigned(uint32_t, *tl++); nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); highest_slotid = fxdr_unsigned(uint32_t, *tl++); if (*tl == newnfs_true) cache_this = 1; else cache_this = 0; nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, &target_highest_slotid, cache_this, &sflags, p); if (nd->nd_repstat != NFSERR_BADSLOT) nd->nd_flag |= ND_HASSEQUENCE; if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(sequenceid); *tl++ = txdr_unsigned(nd->nd_slotid); *tl++ = txdr_unsigned(highest_slotid); *tl++ = txdr_unsigned(target_highest_slotid); *tl = txdr_unsigned(sflags); } nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 reclaim complete service */ int nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; int error = 0, onefs; NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); /* * I believe that a ReclaimComplete with rca_one_fs == TRUE is only * to be used after a file system has been transferred to a different * file server. However, RFC5661 is somewhat vague w.r.t. this and * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. * Therefore, just ignore the rca_one_fs == TRUE operation and return * NFS_OK without doing anything. */ onefs = 0; if (*tl == newnfs_true) onefs = 1; nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 destroy clientid service */ int nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; nfsquad_t clientid; int error = 0; struct thread *p = curthread; if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); clientid.lval[0] = *tl++; clientid.lval[1] = *tl; nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p); nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 bind connection to session service */ int nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; uint8_t sessid[NFSX_V4SESSIONID]; int error = 0, foreaft; if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); foreaft = fxdr_unsigned(int, *tl++); if (*tl == newnfs_true) { /* RDMA is not supported. */ nd->nd_repstat = NFSERR_NOTSUPP; goto nfsmout; } nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); *tl++ = txdr_unsigned(foreaft); *tl = newnfs_false; } nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 destroy session service */ int nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint8_t *cp, sessid[NFSX_V4SESSIONID]; int error = 0; if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); nd->nd_repstat = nfsrv_destroysession(nd, sessid); nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 free stateid service */ int nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; nfsv4stateid_t stateid; int error = 0; struct thread *p = curthread; NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); stateid.seqid = fxdr_unsigned(uint32_t, *tl++); NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); /* * For the special stateid of other all 0s and seqid == 1, set the * stateid to the current stateid, if it is set. */ if (stateid.seqid == 1 && stateid.other[0] == 0 && stateid.other[1] == 0 && stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stateid = nd->nd_curstateid; stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); /* If the current stateid has been free'd, unset it. */ if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && stateid.other[0] == nd->nd_curstateid.other[0] && stateid.other[1] == nd->nd_curstateid.other[1] && stateid.other[2] == nd->nd_curstateid.other[2]) nd->nd_flag &= ~ND_CURSTATEID; nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 layoutget service */ int nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { uint32_t *tl; nfsv4stateid_t stateid; int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; uint64_t offset, len, minlen; char *layp; struct thread *p = curthread; NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + NFSX_STATEID); tl++; /* Signal layout available. Ignore for now. */ layouttype = fxdr_unsigned(int, *tl++); iomode = fxdr_unsigned(int, *tl++); offset = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); tl += 2; minlen = fxdr_hyper(tl); tl += 2; stateid.seqid = fxdr_unsigned(uint32_t, *tl++); NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); maxcnt = fxdr_unsigned(int, *tl); NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, (uintmax_t)minlen); if (len < minlen || (minlen != UINT64_MAX && offset + minlen < offset) || (len != UINT64_MAX && offset + len < offset)) { nd->nd_repstat = NFSERR_INVAL; goto nfsmout; } /* * For the special stateid of other all 0s and seqid == 1, set the * stateid to the current stateid, if it is set. */ if (stateid.seqid == 1 && stateid.other[0] == 0 && stateid.other[1] == 0 && stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stateid = nd->nd_curstateid; stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } layp = NULL; if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); else if (layouttype == NFSLAYOUT_FLEXFILE) layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, M_WAITOK); else nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; if (layp != NULL) nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, &iomode, &offset, &len, minlen, &stateid, maxcnt, &retonclose, &layoutlen, layp, nd->nd_cred, p); NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, layoutlen); if (nd->nd_repstat == 0) { /* For NFSv4.1, set the Current StateID. */ if ((nd->nd_flag & ND_NFSV41) != 0) { nd->nd_curstateid = stateid; nd->nd_flag |= ND_CURSTATEID; } NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 2 * NFSX_HYPER); *tl++ = txdr_unsigned(retonclose); *tl++ = txdr_unsigned(stateid.seqid); NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); *tl++ = txdr_unsigned(1); /* Only returns one layout. */ txdr_hyper(offset, tl); tl += 2; txdr_hyper(len, tl); tl += 2; *tl++ = txdr_unsigned(iomode); *tl = txdr_unsigned(layouttype); nfsm_strtom(nd, layp, layoutlen); } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = newnfs_false; } free(layp, M_TEMP); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 layoutcommit service */ int nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { uint32_t *tl; nfsv4stateid_t stateid; int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; int hasnewsize; uint64_t offset, len, newoff = 0, newsize; struct timespec newmtime; char *layp; struct thread *p = curthread; layp = NULL; NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + NFSX_STATEID); offset = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); tl += 2; reclaim = fxdr_unsigned(int, *tl++); stateid.seqid = fxdr_unsigned(uint32_t, *tl++); NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); /* * For the special stateid of other all 0s and seqid == 1, set the * stateid to the current stateid, if it is set. */ if (stateid.seqid == 1 && stateid.other[0] == 0 && stateid.other[1] == 0 && stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stateid = nd->nd_curstateid; stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } hasnewoff = fxdr_unsigned(int, *tl); if (hasnewoff != 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); newoff = fxdr_hyper(tl); tl += 2; } else NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); hasnewmtime = fxdr_unsigned(int, *tl); if (hasnewmtime != 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); fxdr_nfsv4time(tl, &newmtime); tl += (NFSX_V4TIME / NFSX_UNSIGNED); } else NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); layouttype = fxdr_unsigned(int, *tl++); maxcnt = fxdr_unsigned(int, *tl); if (maxcnt > 0) { layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); error = nfsrv_mtostr(nd, layp, maxcnt); if (error != 0) goto nfsmout; } nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); if (nd->nd_repstat == 0) { if (hasnewsize != 0) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); *tl++ = newnfs_true; txdr_hyper(newsize, tl); } else { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = newnfs_false; } } nfsmout: free(layp, M_TEMP); vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 layoutreturn service */ int nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { uint32_t *tl, *layp; nfsv4stateid_t stateid; int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; uint64_t offset, len; struct thread *p = curthread; layp = NULL; NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); reclaim = *tl++; layouttype = fxdr_unsigned(int, *tl++); iomode = fxdr_unsigned(int, *tl++); kind = fxdr_unsigned(int, *tl); NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, layouttype, iomode, kind); if (kind == NFSV4LAYOUTRET_FILE) { NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + NFSX_UNSIGNED); offset = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); tl += 2; stateid.seqid = fxdr_unsigned(uint32_t, *tl++); NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); /* * For the special stateid of other all 0s and seqid == 1, set * the stateid to the current stateid, if it is set. */ if (stateid.seqid == 1 && stateid.other[0] == 0 && stateid.other[1] == 0 && stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stateid = nd->nd_curstateid; stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } maxcnt = fxdr_unsigned(int, *tl); /* * There is no fixed upper bound defined in the RFCs, * but 128Kbytes should be more than sufficient. */ if (maxcnt < 0 || maxcnt > 131072) maxcnt = 0; if (maxcnt > 0) { layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); error = nfsrv_mtostr(nd, (char *)layp, maxcnt); if (error != 0) goto nfsmout; } } else { if (reclaim == newnfs_true) { nd->nd_repstat = NFSERR_INVAL; goto nfsmout; } offset = len = 0; maxcnt = 0; } nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, nd->nd_cred, p); NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, fnd); if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); if (fnd != 0) { *tl = newnfs_true; NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); *tl++ = txdr_unsigned(stateid.seqid); NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); } else *tl = newnfs_false; } nfsmout: free(layp, M_TEMP); vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 layout error service */ int nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { uint32_t *tl; nfsv4stateid_t stateid; int cnt, error = 0, i, stat; int opnum __unused; char devid[NFSX_V4DEVICEID]; uint64_t offset, len; NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + NFSX_UNSIGNED); offset = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); tl += 2; stateid.seqid = fxdr_unsigned(uint32_t, *tl++); NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); cnt = fxdr_unsigned(int, *tl); NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset, (uintmax_t)len, cnt); /* * For the special stateid of other all 0s and seqid == 1, set * the stateid to the current stateid, if it is set. */ if (stateid.seqid == 1 && stateid.other[0] == 0 && stateid.other[1] == 0 && stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stateid = nd->nd_curstateid; stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } /* * Ignore offset, len and stateid for now. */ for (i = 0; i < cnt; i++) { NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED); NFSBCOPY(tl, devid, NFSX_V4DEVICEID); tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); stat = fxdr_unsigned(int, *tl++); opnum = fxdr_unsigned(int, *tl); NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat); /* * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC * errors, disable the mirror. */ if (stat != NFSERR_ACCES && stat != NFSERR_STALE && stat != NFSERR_NOSPC) nfsrv_delds(devid, curthread); /* For NFSERR_NOSPC, mark all deviceids and layouts. */ if (stat == NFSERR_NOSPC) nfsrv_marknospc(devid, true); } nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 layout stats service */ int nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { uint32_t *tl; nfsv4stateid_t stateid; int cnt, error = 0; int layouttype __unused; char devid[NFSX_V4DEVICEID] __unused; uint64_t offset __unused, len __unused, readcount __unused; uint64_t readbytes __unused, writecount __unused, writebytes __unused; NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID + NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED); offset = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); tl += 2; stateid.seqid = fxdr_unsigned(uint32_t, *tl++); NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); readcount = fxdr_hyper(tl); tl += 2; readbytes = fxdr_hyper(tl); tl += 2; writecount = fxdr_hyper(tl); tl += 2; writebytes = fxdr_hyper(tl); tl += 2; NFSBCOPY(tl, devid, NFSX_V4DEVICEID); tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); layouttype = fxdr_unsigned(int, *tl++); cnt = fxdr_unsigned(int, *tl); error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1); if (error != 0) goto nfsmout; NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt); /* * For the special stateid of other all 0s and seqid == 1, set * the stateid to the current stateid, if it is set. */ if (stateid.seqid == 1 && stateid.other[0] == 0 && stateid.other[1] == 0 && stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stateid = nd->nd_curstateid; stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } /* * No use for the stats for now. */ nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 io_advise service */ int nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { uint32_t *tl; nfsv4stateid_t stateid; nfsattrbit_t hints; int error = 0, ret; off_t offset, len; NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); stateid.seqid = fxdr_unsigned(uint32_t, *tl++); NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); offset = fxdr_hyper(tl); tl += 2; len = fxdr_hyper(tl); error = nfsrv_getattrbits(nd, &hints, NULL, NULL); if (error != 0) goto nfsmout; /* * For the special stateid of other all 0s and seqid == 1, set * the stateid to the current stateid, if it is set. */ if (stateid.seqid == 1 && stateid.other[0] == 0 && stateid.other[1] == 0 && stateid.other[2] == 0) { if ((nd->nd_flag & ND_CURSTATEID) != 0) { stateid = nd->nd_curstateid; stateid.seqid = 0; } else { nd->nd_repstat = NFSERR_BADSTATEID; goto nfsmout; } } if (offset < 0) { nd->nd_repstat = NFSERR_INVAL; goto nfsmout; } if (len < 0) len = 0; if (vp->v_type != VREG) { if (vp->v_type == VDIR) nd->nd_repstat = NFSERR_ISDIR; else nd->nd_repstat = NFSERR_WRONGTYPE; goto nfsmout; } /* * For now, we can only handle WILLNEED and DONTNEED and don't use * the stateid. */ if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) && !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) || (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) && !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) { NFSVOPUNLOCK(vp); if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) { ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED); NFSZERO_ATTRBIT(&hints); if (ret == 0) NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); else NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); } else { ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED); NFSZERO_ATTRBIT(&hints); if (ret == 0) NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); else NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); } vrele(vp); } else { NFSZERO_ATTRBIT(&hints); NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); vput(vp); } nfsrv_putattrbit(nd, &hints); NFSEXITCODE2(error, nd); return (error); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 getdeviceinfo service */ int nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; int cnt, devaddrlen, error = 0, i, layouttype; char devid[NFSX_V4DEVICEID], *devaddr; time_t dev_time; NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); NFSBCOPY(tl, devid, NFSX_V4DEVICEID); tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); layouttype = fxdr_unsigned(int, *tl++); maxcnt = fxdr_unsigned(uint32_t, *tl++); cnt = fxdr_unsigned(int, *tl); NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, maxcnt, cnt); if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { nd->nd_repstat = NFSERR_INVAL; goto nfsmout; } if (cnt > 0) { NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); for (i = 0; i < cnt; i++) notify[i] = fxdr_unsigned(uint32_t, *tl++); } for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) notify[i] = 0; /* * Check that the device id is not stale. Device ids are recreated * each time the nfsd threads are restarted. */ NFSBCOPY(devid, &dev_time, sizeof(dev_time)); if (dev_time != nfsdev_time) { nd->nd_repstat = NFSERR_NOENT; goto nfsmout; } /* Look for the device id. */ nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, notify, &devaddrlen, &devaddr); NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(layouttype); nfsm_strtom(nd, devaddr, devaddrlen); cnt = 0; for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { if (notify[i] != 0) cnt = i + 1; } NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); *tl++ = txdr_unsigned(cnt); for (i = 0; i < cnt; i++) *tl++ = txdr_unsigned(notify[i]); } else if (nd->nd_repstat == NFSERR_TOOSMALL) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(maxcnt); } nfsmout: NFSEXITCODE2(error, nd); return (error); } /* * nfsv4 test stateid service */ int nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; nfsv4stateid_t *stateidp = NULL, *tstateidp; int cnt, error = 0, i, ret; struct thread *p = curthread; NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); cnt = fxdr_unsigned(int, *tl); if (cnt <= 0 || cnt > 1024) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); tstateidp = stateidp; for (i = 0; i < cnt; i++) { NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); tstateidp++; } NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(cnt); tstateidp = stateidp; for (i = 0; i < cnt; i++) { ret = nfsrv_teststateid(nd, tstateidp, p); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(ret); tstateidp++; } nfsmout: free(stateidp, M_TEMP); NFSEXITCODE2(error, nd); return (error); } /* * nfs allocate service */ int nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { uint32_t *tl; struct nfsvattr forat; int error = 0, forat_ret = 1, gotproxystateid; off_t off, len; struct nfsstate st, *stp = &st; struct nfslock lo, *lop = &lo; nfsv4stateid_t stateid; nfsquad_t clientid; nfsattrbit_t attrbits; if (!nfsrv_doallocate) { /* * If any exported file system, such as a ZFS one, cannot * do VOP_ALLOCATE(), this operation cannot be supported * for NFSv4.2. This cannot be done 'per filesystem', but * must be for the entire nfsd NFSv4.2 service. */ nd->nd_repstat = NFSERR_NOTSUPP; goto nfsmout; } gotproxystateid = 0; NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); lop->lo_flags = NFSLCK_WRITE; stp->ls_ownerlen = 0; stp->ls_op = NULL; stp->ls_uid = nd->nd_cred->cr_uid; stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK2 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } stp->ls_stateid.other[2] = *tl++; /* * Don't allow this to be done for a DS. */ if ((nd->nd_flag & ND_DSSERVER) != 0) nd->nd_repstat = NFSERR_NOTSUPP; /* However, allow the proxy stateid. */ if (stp->ls_stateid.seqid == 0xffffffff && stp->ls_stateid.other[0] == 0x55555555 && stp->ls_stateid.other[1] == 0x55555555 && stp->ls_stateid.other[2] == 0x55555555) gotproxystateid = 1; off = fxdr_hyper(tl); tl += 2; lop->lo_first = off; len = fxdr_hyper(tl); lop->lo_end = lop->lo_first + len; /* * Sanity check the offset and length. * off and len are off_t (signed int64_t) whereas * lo_first and lo_end are uint64_t and, as such, * if off >= 0 && len > 0, lo_end cannot overflow * unless off_t is changed to something other than * int64_t. Check lo_end < lo_first in case that * is someday the case. */ if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end > OFF_MAX || lop->lo_end < lop->lo_first)) nd->nd_repstat = NFSERR_INVAL; if (nd->nd_repstat == 0 && vp->v_type != VREG) nd->nd_repstat = NFSERR_WRONGTYPE; NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); if (nd->nd_repstat == 0) nd->nd_repstat = forat_ret; if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || NFSVNO_EXSTRICTACCESS(exp))) nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); if (nd->nd_repstat == 0 && gotproxystateid == 0) nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, &stateid, exp, nd, curthread); NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n", (intmax_t)off, (intmax_t)len, nd->nd_repstat); if (nd->nd_repstat == 0) nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred, curthread); NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n", nd->nd_repstat); vput(vp); NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfs deallocate service */ int nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { uint32_t *tl; struct nfsvattr forat; int error = 0, forat_ret = 1, gotproxystateid; off_t off, len; struct nfsstate st, *stp = &st; struct nfslock lo, *lop = &lo; nfsv4stateid_t stateid; nfsquad_t clientid; nfsattrbit_t attrbits; gotproxystateid = 0; NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); lop->lo_flags = NFSLCK_WRITE; stp->ls_ownerlen = 0; stp->ls_op = NULL; stp->ls_uid = nd->nd_cred->cr_uid; stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { if ((nd->nd_flag & ND_NFSV41) != 0) clientid.qval = nd->nd_clientid.qval; else if (nd->nd_clientid.qval != clientid.qval) printf("EEK2 multiple clids\n"); } else { if ((nd->nd_flag & ND_NFSV41) != 0) printf("EEK! no clientid from session\n"); nd->nd_flag |= ND_IMPLIEDCLID; nd->nd_clientid.qval = clientid.qval; } stp->ls_stateid.other[2] = *tl++; /* * Don't allow this to be done for a DS. */ if ((nd->nd_flag & ND_DSSERVER) != 0) nd->nd_repstat = NFSERR_NOTSUPP; /* However, allow the proxy stateid. */ if (stp->ls_stateid.seqid == 0xffffffff && stp->ls_stateid.other[0] == 0x55555555 && stp->ls_stateid.other[1] == 0x55555555 && stp->ls_stateid.other[2] == 0x55555555) gotproxystateid = 1; off = fxdr_hyper(tl); tl += 2; lop->lo_first = off; len = fxdr_hyper(tl); if (len < 0) len = OFF_MAX; NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off, (intmax_t)len); lop->lo_end = lop->lo_first + len; /* * Sanity check the offset and length. * off and len are off_t (signed int64_t) whereas * lo_first and lo_end are uint64_t and, as such, * if off >= 0 && len > 0, lo_end cannot overflow * unless off_t is changed to something other than * int64_t. Check lo_end < lo_first in case that * is someday the case. * The error to return is not specified by RFC 7862 so I * made this compatible with the Linux knfsd. */ if (nd->nd_repstat == 0) { if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE) nd->nd_repstat = NFSERR_FBIG; else if (len == 0 || lop->lo_end < lop->lo_first) nd->nd_repstat = NFSERR_INVAL; } if (nd->nd_repstat == 0 && vp->v_type != VREG) nd->nd_repstat = NFSERR_WRONGTYPE; NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); if (nd->nd_repstat == 0) nd->nd_repstat = forat_ret; if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || NFSVNO_EXSTRICTACCESS(exp))) nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); if (nd->nd_repstat == 0 && gotproxystateid == 0) nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, &stateid, exp, nd, curthread); if (nd->nd_repstat == 0) nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred, curthread); vput(vp); NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat); NFSEXITCODE2(0, nd); return (0); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfs copy service */ int nfsrvd_copy_file_range(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 cnt, 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; rl_rcookie = rl_wcookie = NULL; if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0) { /* * For a pNFS server, reply NFSERR_NOTSUPP so that the client * will do the copy via I/O on the DS(s). * If vfs.nfsd.maxcopyrange set to 0, disable Copy. */ nd->nd_repstat = NFSERR_NOTSUPP; goto nfsmout; } if (vp == tovp) { /* Copying a byte range within the same file is not allowed. */ nd->nd_repstat = NFSERR_INVAL; goto nfsmout; } NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 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); tl += 2; 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; } /* * At this time only consecutive, synchronous copy is supported, * so ca_consecutive and ca_synchronous can be ignored. */ tl += 2; cnt = fxdr_unsigned(int, *tl); if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0) nd->nd_repstat = NFSERR_NOTSUPP; if (nd->nd_repstat == 0 && (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); NFSVOPUNLOCK(vp); if (nd->nd_repstat != 0) goto out; error = NFSVOPLOCK(tovp, LK_SHARED); if (error != 0) goto out; 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); rl_rcookie = vn_rangelock_tryrlock(vp, inoff, OFF_MAX); } else { rl_wcookie = vn_rangelock_wlock(tovp, outoff, outoff + len); rl_rcookie = vn_rangelock_tryrlock(vp, inoff, inoff + len); } if (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) { /* * If len == 0, set it based on invp's * size. If offset is past EOF, just * leave len == 0. */ len = at.na_size - inoff; } else if (nfsrv_linux42server == 0 && inoff + len > at.na_size) { /* * RFC-7862 says that NFSERR_INVAL must * be returned when inoff + len exceeds * the file size, however the NFSv4.2 * Linux client likes to do this, so * only check if nfsrv_linux42server * is not set. */ 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. */ if (len > nfsrv_maxcopyrange) xfer = nfsrv_maxcopyrange; else xfer = len; if (nd->nd_repstat == 0) { nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred, NULL); if (nd->nd_repstat == 0) len = xfer; } /* Unlock the ranges. */ if (rl_rcookie != NULL) vn_rangelock_unlock(vp, rl_rcookie); if (rl_wcookie != NULL) vn_rangelock_unlock(tovp, rl_wcookie); if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER + NFSX_VERF); *tl++ = txdr_unsigned(0); /* No callback ids. */ txdr_hyper(len, tl); tl += 2; *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE); *tl++ = txdr_unsigned(nfsboottime.tv_sec); *tl++ = txdr_unsigned(nfsboottime.tv_usec); *tl++ = newnfs_true; *tl = newnfs_true; } out: vrele(vp); vrele(tovp); NFSEXITCODE2(error, nd); return (error); nfsmout: vput(vp); vrele(tovp); NFSEXITCODE2(error, nd); return (error); } /* * 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 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, struct nfsexstuff *exp) { uint32_t *tl; struct nfsvattr at; int content, error = 0; off_t off; u_long cmd; nfsattrbit_t attrbits; bool eof; NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED); /* Ignore the stateid for now. */ tl += (NFSX_STATEID / NFSX_UNSIGNED); off = fxdr_hyper(tl); tl += 2; content = fxdr_unsigned(int, *tl); if (content == NFSV4CONTENT_DATA) cmd = FIOSEEKDATA; else if (content == NFSV4CONTENT_HOLE) cmd = FIOSEEKHOLE; else nd->nd_repstat = NFSERR_BADXDR; if (nd->nd_repstat == 0 && vp->v_type == VDIR) nd->nd_repstat = NFSERR_ISDIR; if (nd->nd_repstat == 0 && vp->v_type != VREG) nd->nd_repstat = NFSERR_WRONGTYPE; if (nd->nd_repstat == 0 && off < 0) nd->nd_repstat = NFSERR_NXIO; if (nd->nd_repstat == 0) { /* Check permissions for the input file. */ NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); } 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) goto nfsmout; /* nfsvno_seek() unlocks and vrele()s the vp. */ nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof, nd->nd_cred, curthread); if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA && nfsrv_linux42server != 0) nd->nd_repstat = NFSERR_NXIO; if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); if (eof) *tl++ = newnfs_true; else *tl++ = newnfs_false; txdr_hyper(off, tl); } NFSEXITCODE2(error, nd); return (error); nfsmout: vput(vp); NFSEXITCODE2(error, nd); return (error); } /* * nfs get extended attribute service */ int nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; struct mbuf *mp = NULL, *mpend = NULL; int error, len; char *name; struct thread *p = curthread; uint16_t off; error = 0; NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(int, *tl); if (len <= 0) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } if (len > EXTATTR_MAXNAMELEN) { nd->nd_repstat = NFSERR_NOXATTR; goto nfsmout; } name = malloc(len + 1, M_TEMP, M_WAITOK); nd->nd_repstat = nfsrv_mtostr(nd, name, len); if (nd->nd_repstat == 0) nd->nd_repstat = nfsvno_getxattr(vp, name, nd->nd_maxresp, nd->nd_cred, nd->nd_flag, nd->nd_maxextsiz, p, &mp, &mpend, &len); if (nd->nd_repstat == ENOATTR) nd->nd_repstat = NFSERR_NOXATTR; else if (nd->nd_repstat == EOPNOTSUPP) nd->nd_repstat = NFSERR_NOTSUPP; if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(len); if (len > 0) { nd->nd_mb->m_next = mp; nd->nd_mb = mpend; if ((mpend->m_flags & M_EXTPG) != 0) { nd->nd_flag |= ND_EXTPG; nd->nd_bextpg = mpend->m_epg_npgs - 1; nd->nd_bpos = (char *)(void *) PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0; nd->nd_bpos += off + mpend->m_epg_last_len; nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len - off; } else nd->nd_bpos = mtod(mpend, char *) + mpend->m_len; } } free(name, M_TEMP); nfsmout: if (nd->nd_repstat == 0) nd->nd_repstat = error; vput(vp); NFSEXITCODE2(0, nd); return (0); } /* * nfs set extended attribute service */ int nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; struct nfsvattr ova, nva; nfsattrbit_t attrbits; int error, len, opt; char *name; size_t siz; struct thread *p = curthread; error = 0; name = NULL; NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); opt = fxdr_unsigned(int, *tl++); len = fxdr_unsigned(int, *tl); if (len <= 0) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } if (len > EXTATTR_MAXNAMELEN) { nd->nd_repstat = NFSERR_NOXATTR; goto nfsmout; } name = malloc(len + 1, M_TEMP, M_WAITOK); error = nfsrv_mtostr(nd, name, len); if (error != 0) goto nfsmout; NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(int, *tl); if (len < 0 || len > IOSIZE_MAX) { nd->nd_repstat = NFSERR_XATTR2BIG; goto nfsmout; } switch (opt) { case NFSV4SXATTR_CREATE: error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, &siz, nd->nd_cred, p); if (error != ENOATTR) nd->nd_repstat = NFSERR_EXIST; error = 0; break; case NFSV4SXATTR_REPLACE: error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, &siz, nd->nd_cred, p); if (error != 0) nd->nd_repstat = NFSERR_NOXATTR; break; case NFSV4SXATTR_EITHER: break; default: nd->nd_repstat = NFSERR_BADXDR; } if (nd->nd_repstat != 0) goto nfsmout; /* Now, do the Set Extended attribute, with Change before and after. */ NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); if (nd->nd_repstat == 0) { nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md, nd->nd_dpos, nd->nd_cred, p); if (nd->nd_repstat == ENXIO) nd->nd_repstat = NFSERR_XATTR2BIG; } if (nd->nd_repstat == 0 && len > 0) nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1); if (nd->nd_repstat == 0) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); *tl++ = newnfs_true; txdr_hyper(ova.na_filerev, tl); tl += 2; txdr_hyper(nva.na_filerev, tl); } nfsmout: free(name, M_TEMP); if (nd->nd_repstat == 0) nd->nd_repstat = error; vput(vp); NFSEXITCODE2(0, nd); return (0); } /* * nfs remove extended attribute service */ int nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t *tl; struct nfsvattr ova, nva; nfsattrbit_t attrbits; int error, len; char *name; struct thread *p = curthread; error = 0; name = NULL; NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); len = fxdr_unsigned(int, *tl); if (len <= 0) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } if (len > EXTATTR_MAXNAMELEN) { nd->nd_repstat = NFSERR_NOXATTR; goto nfsmout; } name = malloc(len + 1, M_TEMP, M_WAITOK); error = nfsrv_mtostr(nd, name, len); if (error != 0) goto nfsmout; if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) { printf("EEK! nfsrvd_rmxattr: no implied clientid\n"); error = NFSERR_NOXATTR; goto nfsmout; } /* * Now, do the Remove Extended attribute, with Change before and * after. */ NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); if (nd->nd_repstat == 0) { nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p); if (nd->nd_repstat == ENOATTR) nd->nd_repstat = NFSERR_NOXATTR; } if (nd->nd_repstat == 0) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); if (nd->nd_repstat == 0) { NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); *tl++ = newnfs_true; txdr_hyper(ova.na_filerev, tl); tl += 2; txdr_hyper(nva.na_filerev, tl); } nfsmout: free(name, M_TEMP); if (nd->nd_repstat == 0) nd->nd_repstat = error; vput(vp); NFSEXITCODE2(0, nd); return (0); } /* * nfs list extended attribute service */ int nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, __unused struct nfsexstuff *exp) { uint32_t cnt, *tl, len, len2, i, pos, retlen; int error; uint64_t cookie, cookie2; u_char *buf; bool eof; struct thread *p = curthread; error = 0; buf = NULL; NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); /* * The cookie doesn't need to be in net byte order, but FreeBSD * does so to make it more readable in packet traces. */ cookie = fxdr_hyper(tl); tl += 2; len = fxdr_unsigned(uint32_t, *tl); if (len == 0 || cookie >= IOSIZE_MAX) { nd->nd_repstat = NFSERR_BADXDR; goto nfsmout; } if (len > nd->nd_maxresp - NFS_MAXXDR) len = nd->nd_maxresp - NFS_MAXXDR; len2 = len; nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf, &len, &eof); if (nd->nd_repstat == EOPNOTSUPP) nd->nd_repstat = NFSERR_NOTSUPP; if (nd->nd_repstat == 0) { cookie2 = cookie + len; if (cookie2 < cookie) nd->nd_repstat = NFSERR_BADXDR; } retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED; if (nd->nd_repstat == 0 && len2 < retlen) nd->nd_repstat = NFSERR_TOOSMALL; if (nd->nd_repstat == 0) { /* Now copy the entries out. */ if (len == 0) { /* The cookie was at eof. */ NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); txdr_hyper(cookie2, tl); tl += 2; *tl++ = txdr_unsigned(0); *tl = newnfs_true; goto nfsmout; } /* Sanity check the cookie. */ for (pos = 0; pos < len; pos += (i + 1)) { if (pos == cookie) break; i = buf[pos]; } if (pos != cookie) { nd->nd_repstat = NFSERR_INVAL; goto nfsmout; } /* Loop around copying the entrie(s) out. */ cnt = 0; len -= cookie; i = buf[pos]; while (i < len && len2 >= retlen + NFSM_RNDUP(i) + NFSX_UNSIGNED) { if (cnt == 0) { NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); txdr_hyper(cookie2, tl); tl += 2; } retlen += nfsm_strtom(nd, &buf[pos + 1], i); len -= (i + 1); pos += (i + 1); i = buf[pos]; cnt++; } /* * eof is set true/false by nfsvno_listxattr(), but if we * can't copy all entries returned by nfsvno_listxattr(), * we are not at eof. */ if (len > 0) eof = false; if (cnt > 0) { /* *tl is set above. */ *tl = txdr_unsigned(cnt); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); if (eof) *tl = newnfs_true; else *tl = newnfs_false; } else nd->nd_repstat = NFSERR_TOOSMALL; } nfsmout: free(buf, M_TEMP); if (nd->nd_repstat == 0) nd->nd_repstat = error; vput(vp); NFSEXITCODE2(0, nd); return (0); } /* * nfsv4 service not supported */ int nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, __unused vnode_t vp, __unused struct nfsexstuff *exp) { nd->nd_repstat = NFSERR_NOTSUPP; NFSEXITCODE2(0, nd); return (0); } diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c index 636c4735a131..201f3b74b946 100644 --- a/sys/fs/nfsserver/nfs_nfsdsocket.c +++ b/sys/fs/nfsserver/nfs_nfsdsocket.c @@ -1,1436 +1,1436 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 /* * Socket operations for use by the nfs server. */ #include #include extern struct nfsrvfh nfs_pubfh; extern int nfs_pubfhset; extern struct nfsv4lock nfsv4rootfs_lock; extern int nfsrv_clienthashsize; extern int nfsd_debuglevel; extern int nfsrv_layouthighwater; extern volatile int nfsrv_layoutcnt; NFSV4ROOTLOCKMUTEX; NFSSTATESPINLOCK; NFSD_VNET_DECLARE(struct nfsrv_stablefirst, nfsrv_stablefirst); NFSD_VNET_DECLARE(struct nfsclienthashhead *, nfsclienthash); NFSD_VNET_DECLARE(int, nfsrc_floodlevel); NFSD_VNET_DECLARE(int, nfsrc_tcpsavedreplies); NFSD_VNET_DECLARE(struct nfsrvfh, nfs_rootfh); NFSD_VNET_DECLARE(int, nfs_rootfhset); NFSD_VNET_DECLARE(struct nfsstatsv1 *, nfsstatsv1_p); int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *) = { (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_getattr, nfsrvd_setattr, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_access, nfsrvd_readlink, nfsrvd_read, nfsrvd_write, nfsrvd_create, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_remove, nfsrvd_remove, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_readdir, nfsrvd_readdirplus, nfsrvd_statfs, nfsrvd_fsinfo, nfsrvd_pathconf, nfsrvd_commit, }; int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = { (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, nfsrvd_lookup, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, nfsrvd_mkdir, nfsrvd_symlink, nfsrvd_mknod, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, }; int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = { (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, (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, (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, (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_rename, nfsrvd_link, (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, (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 (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *) = { (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_access, nfsrvd_close, nfsrvd_commit, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_delegpurge, nfsrvd_delegreturn, nfsrvd_getattr, nfsrvd_getfh, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_lock, nfsrvd_lockt, nfsrvd_locku, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_verify, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_openconfirm, nfsrvd_opendowngrade, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_read, nfsrvd_readdirplus, nfsrvd_readlink, nfsrvd_remove, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_renew, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_secinfo, nfsrvd_setattr, nfsrvd_setclientid, nfsrvd_setclientidcfrm, nfsrvd_verify, nfsrvd_write, nfsrvd_releaselckown, nfsrvd_notsupp, nfsrvd_bindconnsess, nfsrvd_exchangeid, nfsrvd_createsession, nfsrvd_destroysession, nfsrvd_freestateid, nfsrvd_notsupp, nfsrvd_getdevinfo, nfsrvd_notsupp, nfsrvd_layoutcommit, nfsrvd_layoutget, nfsrvd_layoutreturn, nfsrvd_secinfononame, nfsrvd_sequence, nfsrvd_notsupp, nfsrvd_teststateid, nfsrvd_notsupp, nfsrvd_destroyclientid, nfsrvd_reclaimcomplete, nfsrvd_allocate, (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, nfsrvd_notsupp, nfsrvd_deallocate, nfsrvd_ioadvise, nfsrvd_layouterror, nfsrvd_layoutstats, nfsrvd_notsupp, nfsrvd_notsupp, nfsrvd_notsupp, nfsrvd_seek, nfsrvd_notsupp, nfsrvd_notsupp, nfsrvd_getxattr, nfsrvd_setxattr, nfsrvd_listxattr, nfsrvd_rmxattr, }; int (*nfsrv4_ops1[NFSV42_NOPS])(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *) = { (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, nfsrvd_mknod, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, nfsrvd_lookup, nfsrvd_lookup, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, nfsrvd_open, nfsrvd_openattr, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, struct nfsexstuff *))0, }; int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *) = { (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, (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, (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_link, (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, (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, (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, (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, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, nfsrvd_rename, (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, (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, (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, (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, (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, (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, (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, (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_copy_file_range, (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, (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, (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, (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0, }; /* * Static array that defines which nfs rpc's are nonidempotent */ static int nfsrv_nonidempotent[NFS_V3NPROCS] = { FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, }; /* * This static array indicates whether or not the RPC modifies the * file system. */ int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; SYSCTL_DECL(_vfs_nfsd); static int nfs_minminorv4 = NFSV4_MINORVERSION; SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_minorversion4, CTLFLAG_RWTUN, &nfs_minminorv4, 0, "The lowest minor version of NFSv4 handled by the server"); static int nfs_maxminorv4 = NFSV42_MINORVERSION; SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_minorversion4, CTLFLAG_RWTUN, &nfs_maxminorv4, 0, "The highest minor version of NFSv4 handled by the server"); /* local functions */ static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen, u_int32_t minorvers); /* * This static array indicates which server procedures require the extra * arguments to return the current file handle for V2, 3. */ static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 }; extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS]; static int nfsv3to4op[NFS_V3NPROCS] = { NFSPROC_NULL, NFSV4OP_GETATTR, NFSV4OP_SETATTR, NFSV4OP_LOOKUP, NFSV4OP_ACCESS, NFSV4OP_READLINK, NFSV4OP_READ, NFSV4OP_WRITE, NFSV4OP_V3CREATE, NFSV4OP_MKDIR, NFSV4OP_SYMLINK, NFSV4OP_MKNOD, NFSV4OP_REMOVE, NFSV4OP_RMDIR, NFSV4OP_RENAME, NFSV4OP_LINK, NFSV4OP_READDIR, NFSV4OP_READDIRPLUS, NFSV4OP_FSSTAT, NFSV4OP_FSINFO, NFSV4OP_PATHCONF, NFSV4OP_COMMIT, }; static struct mtx nfsrvd_statmtx; MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF); static struct ucred *nfsrv_createrootcred(void); static void nfsrvd_statstart(int op, struct bintime *now) { if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) { printf("%s: op %d invalid\n", __func__, op); return; } mtx_lock(&nfsrvd_statmtx); if (NFSD_VNET(nfsstatsv1_p)->srvstartcnt == NFSD_VNET(nfsstatsv1_p)->srvdonecnt) { if (now != NULL) NFSD_VNET(nfsstatsv1_p)->busyfrom = *now; else binuptime(&NFSD_VNET(nfsstatsv1_p)->busyfrom); } NFSD_VNET(nfsstatsv1_p)->srvrpccnt[op]++; NFSD_VNET(nfsstatsv1_p)->srvstartcnt++; mtx_unlock(&nfsrvd_statmtx); } static void nfsrvd_statend(int op, uint64_t bytes, struct bintime *now, struct bintime *then) { struct bintime dt, lnow; if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) { printf("%s: op %d invalid\n", __func__, op); return; } if (now == NULL) { now = &lnow; binuptime(now); } mtx_lock(&nfsrvd_statmtx); NFSD_VNET(nfsstatsv1_p)->srvbytes[op] += bytes; NFSD_VNET(nfsstatsv1_p)->srvops[op]++; if (then != NULL) { dt = *now; bintime_sub(&dt, then); bintime_add(&NFSD_VNET(nfsstatsv1_p)->srvduration[op], &dt); } dt = *now; bintime_sub(&dt, &NFSD_VNET(nfsstatsv1_p)->busyfrom); bintime_add(&NFSD_VNET(nfsstatsv1_p)->busytime, &dt); NFSD_VNET(nfsstatsv1_p)->busyfrom = *now; NFSD_VNET(nfsstatsv1_p)->srvdonecnt++; mtx_unlock(&nfsrvd_statmtx); } /* * Do an RPC. Basically, get the file handles translated to vnode pointers * and then call the appropriate server routine. The server routines are * split into groups, based on whether they use a file handle or file * handle plus name or ... * The NFS V4 Compound RPC is performed separately by nfsrvd_compound(). */ void nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen, u_int32_t minorvers) { int error = 0, lktype; vnode_t vp; mount_t mp; struct nfsrvfh fh; struct nfsexstuff nes; struct mbuf *md; char *dpos; /* * Save the current position in the request mbuf list so * that a rollback to this location can be done upon an * ERELOOKUP error return from an RPC function. */ md = nd->nd_md; dpos = nd->nd_dpos; tryagain: mp = NULL; /* * Get a locked vnode for the first file handle */ if (!(nd->nd_flag & ND_NFSV4)) { KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc")); /* * For NFSv3, if the malloc/mget allocation is near limits, * return NFSERR_DELAY. */ if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) { nd->nd_repstat = NFSERR_DELAY; vp = NULL; } else { error = nfsrv_mtofh(nd, &fh); if (error) { if (error != EBADRPC) printf("nfs dorpc err1=%d\n", error); nd->nd_repstat = NFSERR_GARBAGE; goto out; } if (nd->nd_procnum == NFSPROC_READ || nd->nd_procnum == NFSPROC_WRITE || nd->nd_procnum == NFSPROC_READDIR || nd->nd_procnum == NFSPROC_READDIRPLUS || nd->nd_procnum == NFSPROC_READLINK || nd->nd_procnum == NFSPROC_GETATTR || nd->nd_procnum == NFSPROC_ACCESS || nd->nd_procnum == NFSPROC_FSSTAT || nd->nd_procnum == NFSPROC_FSINFO) lktype = LK_SHARED; else lktype = LK_EXCLUSIVE; if (nd->nd_flag & ND_PUBLOOKUP) nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes, &mp, nfsrv_writerpc[nd->nd_procnum], -1); else nfsd_fhtovp(nd, &fh, lktype, &vp, &nes, &mp, nfsrv_writerpc[nd->nd_procnum], -1); if (nd->nd_repstat == NFSERR_PROGNOTV4) goto out; } } /* * For V2 and 3, set the ND_SAVEREPLY flag for the recent request * cache, as required. * For V4, nfsrvd_compound() does this. */ if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum]) nd->nd_flag |= ND_SAVEREPLY; nfsrvd_rephead(nd); /* * If nd_repstat is non-zero, just fill in the reply status * to complete the RPC reply for V2. Otherwise, you must do * the RPC. */ if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { *nd->nd_errp = nfsd_errmap(nd); nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL); nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0, /*now*/ NULL, /*then*/ NULL); vn_finished_write(mp); goto out; } /* * Now the procedure can be performed. For V4, nfsrvd_compound() * works through the sub-rpcs, otherwise just call the procedure. * The procedures are in three groups with different arguments. * The group is indicated by the value in nfs_retfh[]. */ if (nd->nd_flag & ND_NFSV4) { nfsrvd_compound(nd, isdgram, tag, taglen, minorvers); } else { struct bintime start_time; binuptime(&start_time); nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time); if (nfs_retfh[nd->nd_procnum] == 1) { if (vp) NFSVOPUNLOCK(vp); error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram, vp, NULL, (fhandle_t *)fh.nfsrvfh_data, &nes); } else if (nfs_retfh[nd->nd_procnum] == 2) { error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram, vp, NULL, &nes, NULL); } else { error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram, vp, &nes); } vn_finished_write(mp); if (error == 0 && nd->nd_repstat == ERELOOKUP) { /* * Roll back to the beginning of the RPC request * arguments. */ nd->nd_md = md; nd->nd_dpos = dpos; /* Free the junk RPC reply and redo the RPC. */ m_freem(nd->nd_mreq); nd->nd_mreq = nd->nd_mb = NULL; nd->nd_repstat = 0; goto tryagain; } nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0, /*now*/ NULL, /*then*/ &start_time); } if (error) { if (error != EBADRPC) printf("nfs dorpc err2=%d\n", error); nd->nd_repstat = NFSERR_GARBAGE; } *nd->nd_errp = nfsd_errmap(nd); /* * Don't cache certain reply status values. */ if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) && (nd->nd_repstat == NFSERR_GARBAGE || nd->nd_repstat == NFSERR_BADXDR || nd->nd_repstat == NFSERR_MOVED || nd->nd_repstat == NFSERR_DELAY || nd->nd_repstat == NFSERR_BADSEQID || nd->nd_repstat == NFSERR_RESOURCE || nd->nd_repstat == NFSERR_SERVERFAULT || nd->nd_repstat == NFSERR_STALECLIENTID || nd->nd_repstat == NFSERR_STALESTATEID || nd->nd_repstat == NFSERR_OLDSTATEID || nd->nd_repstat == NFSERR_BADSTATEID || nd->nd_repstat == NFSERR_GRACE || nd->nd_repstat == NFSERR_NOGRACE)) nd->nd_flag &= ~ND_SAVEREPLY; out: NFSEXITCODE2(0, nd); } /* * Breaks down a compound RPC request and calls the server routines for * the subprocedures. * Some suboperations are performed directly here to simplify file handle<--> * vnode pointer handling. */ static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen, u_int32_t minorvers) { int i, lktype, op, op0 = 0, rstat, statsinprog = 0; u_int32_t *tl; struct nfsclient *clp, *nclp; int error = 0, igotlock, nextop, numops, savefhcnt; u_int32_t retops = 0, *retopsp = NULL, *repp; vnode_t vp, nvp, savevp; struct nfsrvfh fh; mount_t new_mp, temp_mp = NULL; struct ucred *credanon, *rootcred, *savecred; struct nfsexstuff nes, vpnes, savevpnes; fsid_t cur_fsid, save_fsid; static u_int64_t compref = 0; struct bintime start_time; struct thread *p; struct mbuf *mb, *md; char *bpos, *dpos; int bextpg, bextpgsiz; p = curthread; rootcred = savecred = NULL; /* Check for and optionally clear the no space flags for DSs. */ nfsrv_checknospc(); NFSVNO_EXINIT(&vpnes); NFSVNO_EXINIT(&savevpnes); /* * Put the seq# of the current compound RPC in nfsrv_descript. * (This is used by nfsrv_checkgetattr(), to see if the write * delegation was created by the same compound RPC as the one * with that Getattr in it.) * Don't worry about the 64bit number wrapping around. It ain't * gonna happen before this server gets shut down/rebooted. */ nd->nd_compref = compref++; /* * Check for and optionally get a lock on the root. This lock means that * no nfsd will be fiddling with the V4 file system and state stuff. It * is required when the V4 root is being changed, the stable storage * restart file is being updated, or callbacks are being done. * When any of the nfsd are processing an NFSv4 compound RPC, they must * either hold a reference count (nfs_usecnt) or the lock. When * nfsrv_unlock() is called to release the lock, it can optionally * also get a reference count, which saves the need for a call to * nfsrv_getref() after nfsrv_unlock(). */ /* * First, check to see if we need to wait for an update lock. */ igotlock = 0; NFSLOCKV4ROOTMUTEX(); if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NEEDLOCK) igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); else igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); NFSUNLOCKV4ROOTMUTEX(); if (igotlock) { /* * If I got the lock, I can update the stable storage file. * Done when the grace period is over or a client has long * since expired. */ NFSD_VNET(nfsrv_stablefirst).nsf_flags &= ~NFSNSF_NEEDLOCK; if ((NFSD_VNET(nfsrv_stablefirst).nsf_flags & (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER) nfsrv_updatestable(p); /* * If at least one client has long since expired, search * the client list for them, write a REVOKE record on the * stable storage file and then remove them from the client * list. */ if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_EXPIREDCLIENT) { NFSD_VNET(nfsrv_stablefirst).nsf_flags &= ~NFSNSF_EXPIREDCLIENT; for (i = 0; i < nfsrv_clienthashsize; i++) { LIST_FOREACH_SAFE(clp, &NFSD_VNET(nfsclienthash)[i], lc_hash, nclp) { if (clp->lc_flags & LCL_EXPIREIT) { if (!LIST_EMPTY(&clp->lc_open) || !LIST_EMPTY(&clp->lc_deleg)) nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); nfsrv_cleanclient(clp, p, false, NULL); nfsrv_freedeleglist(&clp->lc_deleg); nfsrv_freedeleglist(&clp->lc_olddeleg); LIST_REMOVE(clp, lc_hash); nfsrv_zapclient(clp, p); } } } } NFSLOCKV4ROOTMUTEX(); nfsv4_unlock(&nfsv4rootfs_lock, 1); NFSUNLOCKV4ROOTMUTEX(); } else { /* * If we didn't get the lock, we need to get a refcnt, * which also checks for and waits for the lock. */ NFSLOCKV4ROOTMUTEX(); nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); NFSUNLOCKV4ROOTMUTEX(); } /* * If flagged, search for open owners that haven't had any opens * for a long time. */ if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NOOPENS) { nfsrv_throwawayopens(p); } /* Do a CBLAYOUTRECALL callback if over the high water mark. */ if (nfsrv_layoutcnt > nfsrv_layouthighwater) nfsrv_recalloldlayout(p); savevp = vp = NULL; save_fsid.val[0] = save_fsid.val[1] = 0; cur_fsid.val[0] = cur_fsid.val[1] = 0; nextop = -1; savefhcnt = 0; /* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */ if (taglen < 0) { error = EBADRPC; goto nfsmout; } (void) nfsm_strtom(nd, tag, taglen); NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED); NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); if ((minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION && minorvers != NFSV42_MINORVERSION) || minorvers < nfs_minminorv4 || minorvers > nfs_maxminorv4) nd->nd_repstat = NFSERR_MINORVERMISMATCH; if (nd->nd_repstat) numops = 0; else numops = fxdr_unsigned(int, *tl); /* * Loop around doing the sub ops. * vp - is an unlocked vnode pointer for the CFH * savevp - is an unlocked vnode pointer for the SAVEDFH * (at some future date, it might turn out to be more appropriate * to keep the file handles instead of vnode pointers?) * savevpnes and vpnes - are the export flags for the above. */ for (i = 0; i < numops; i++) { NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED); if (savefhcnt > 0) { op = NFSV4OP_SAVEFH; *repp = txdr_unsigned(op); savefhcnt--; } else if (nextop == -1) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); *repp = *tl; op = fxdr_unsigned(int, *tl); } else { op = nextop; *repp = txdr_unsigned(op); nextop = -1; } NFSD_DEBUG(4, "op=%d\n", op); if (op < NFSV4OP_ACCESS || op >= NFSV42_NOPS || (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) || (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV42) == 0)) { nd->nd_repstat = NFSERR_OPILLEGAL; *repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL); *repp = nfsd_errmap(nd); retops++; break; } else { repp++; } binuptime(&start_time); nfsrvd_statstart(op, &start_time); statsinprog = 1; if (i == 0) op0 = op; if (i == numops - 1) nd->nd_flag |= ND_LASTOP; /* * Check for a referral on the current FH and, if so, return * NFSERR_MOVED for all ops that allow it, except Getattr. */ if (vp != NULL && op != NFSV4OP_GETATTR && nfsv4root_getreferral(vp, NULL, 0) != NULL && nfsrv_errmoved(op)) { nd->nd_repstat = NFSERR_MOVED; *repp = nfsd_errmap(nd); retops++; break; } /* * For NFSv4.1, check for a Sequence Operation being first * or one of the other allowed operations by itself. */ if ((nd->nd_flag & ND_NFSV41) != 0) { if (i != 0 && op == NFSV4OP_SEQUENCE) nd->nd_repstat = NFSERR_SEQUENCEPOS; else if (i == 0 && op != NFSV4OP_SEQUENCE && op != NFSV4OP_EXCHANGEID && op != NFSV4OP_CREATESESSION && op != NFSV4OP_BINDCONNTOSESS && op != NFSV4OP_DESTROYCLIENTID && op != NFSV4OP_DESTROYSESSION) nd->nd_repstat = NFSERR_OPNOTINSESS; else if (i != 0 && op0 != NFSV4OP_SEQUENCE) nd->nd_repstat = NFSERR_NOTONLYOP; if (nd->nd_repstat != 0) { *repp = nfsd_errmap(nd); retops++; break; } } nd->nd_procnum = op; /* * If over flood level, reply NFSERR_RESOURCE, if at the first * Op. (Since a client recovery from NFSERR_RESOURCE can get * really nasty for certain Op sequences, I'll play it safe * and only return the error at the beginning.) The cache * will still function over flood level, but uses lots of * mbufs.) * If nfsrv_mallocmget_limit() returns True, the system is near * to its limit for memory that malloc()/mget() can allocate. */ if (i == 0 && (nd->nd_rp == NULL || nd->nd_rp->rc_refcnt == 0) && (nfsrv_mallocmget_limit() || NFSD_VNET(nfsrc_tcpsavedreplies) > NFSD_VNET(nfsrc_floodlevel))) { if (NFSD_VNET(nfsrc_tcpsavedreplies) > NFSD_VNET(nfsrc_floodlevel)) printf("nfsd server cache flooded, try " "increasing vfs.nfsd.tcphighwater\n"); nd->nd_repstat = NFSERR_RESOURCE; *repp = nfsd_errmap(nd); if (op == NFSV4OP_SETATTR) { /* * Setattr replies require a bitmap. * even for errors like these. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = 0; } retops++; break; } /* * Check for the case of SP4_MACH_CRED and an operation in * the allow set. For these operations, replace nd_cred with * root credentials so that the operation will not fail due * to credentials. * NB: ND_MACHCRED is set by Sequence when the ClientID * specifies LCL_MACHCRED and the RPC is being performed * via krb5i or krb5p using the machine principal. */ if ((nd->nd_flag & ND_MACHCRED) != 0) { if (NFSISSET_OPBIT(&nd->nd_allowops, op)) { /* Replace nd_cred with root creds. */ if (rootcred == NULL) rootcred = nfsrv_createrootcred(); if (savecred == NULL) savecred = nd->nd_cred; nd->nd_cred = rootcred; } else if (savecred != NULL) { nd->nd_cred = savecred; savecred = NULL; } } if (nfsv4_opflag[op].savereply) nd->nd_flag |= ND_SAVEREPLY; switch (op) { case NFSV4OP_PUTFH: error = nfsrv_mtofh(nd, &fh); if (error) goto nfsmout; if ((nd->nd_flag & ND_LASTOP) == 0) { /* * Pre-parse the next op#. If it is * SaveFH, count it and skip to the * next op#, if not the last op#. * nextop is used to determine if * NFSERR_WRONGSEC can be returned, * per RFC5661 Sec. 2.6. */ do { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); nextop = fxdr_unsigned(int, *tl); if (nextop == NFSV4OP_SAVEFH && i < numops - 1) savefhcnt++; } while (nextop == NFSV4OP_SAVEFH && i < numops - 1); } if (!nd->nd_repstat) nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes, NULL, 0, nextop); /* For now, allow this for non-export FHs */ if (!nd->nd_repstat) { if (vp) vrele(vp); vp = nvp; cur_fsid = vp->v_mount->mnt_stat.f_fsid; NFSVOPUNLOCK(vp); vpnes = nes; } break; case NFSV4OP_PUTPUBFH: if (nfs_pubfhset) { if ((nd->nd_flag & ND_LASTOP) == 0) { /* * Pre-parse the next op#. If it is * SaveFH, count it and skip to the * next op#, if not the last op#. * nextop is used to determine if * NFSERR_WRONGSEC can be returned, * per RFC5661 Sec. 2.6. */ do { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); nextop = fxdr_unsigned(int, *tl); if (nextop == NFSV4OP_SAVEFH && i < numops - 1) savefhcnt++; } while (nextop == NFSV4OP_SAVEFH && i < numops - 1); } nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp, &nes, NULL, 0, nextop); } else nd->nd_repstat = NFSERR_NOFILEHANDLE; if (!nd->nd_repstat) { if (vp) vrele(vp); vp = nvp; cur_fsid = vp->v_mount->mnt_stat.f_fsid; NFSVOPUNLOCK(vp); vpnes = nes; } break; case NFSV4OP_PUTROOTFH: if (NFSD_VNET(nfs_rootfhset)) { if ((nd->nd_flag & ND_LASTOP) == 0) { /* * Pre-parse the next op#. If it is * SaveFH, count it and skip to the * next op#, if not the last op#. * nextop is used to determine if * NFSERR_WRONGSEC can be returned, * per RFC5661 Sec. 2.6. */ do { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); nextop = fxdr_unsigned(int, *tl); if (nextop == NFSV4OP_SAVEFH && i < numops - 1) savefhcnt++; } while (nextop == NFSV4OP_SAVEFH && i < numops - 1); } nfsd_fhtovp(nd, &NFSD_VNET(nfs_rootfh), LK_SHARED, &nvp, &nes, NULL, 0, nextop); if (!nd->nd_repstat) { if (vp) vrele(vp); vp = nvp; cur_fsid = vp->v_mount->mnt_stat.f_fsid; NFSVOPUNLOCK(vp); vpnes = nes; } } else nd->nd_repstat = NFSERR_NOFILEHANDLE; break; case NFSV4OP_SAVEFH: if (vp && NFSVNO_EXPORTED(&vpnes)) { nd->nd_repstat = 0; /* If vp == savevp, a no-op */ if (vp != savevp) { if (savevp) vrele(savevp); - VREF(vp); + vref(vp); savevp = vp; savevpnes = vpnes; save_fsid = cur_fsid; } if ((nd->nd_flag & ND_CURSTATEID) != 0) { nd->nd_savedcurstateid = nd->nd_curstateid; nd->nd_flag |= ND_SAVEDCURSTATEID; } } else { nd->nd_repstat = NFSERR_NOFILEHANDLE; } break; case NFSV4OP_RESTOREFH: if (savevp) { if ((nd->nd_flag & ND_LASTOP) == 0) { /* * Pre-parse the next op#. If it is * SaveFH, count it and skip to the * next op#, if not the last op#. * nextop is used to determine if * NFSERR_WRONGSEC can be returned, * per RFC5661 Sec. 2.6. */ do { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); nextop = fxdr_unsigned(int, *tl); if (nextop == NFSV4OP_SAVEFH && i < numops - 1) savefhcnt++; } while (nextop == NFSV4OP_SAVEFH && i < numops - 1); } nd->nd_repstat = 0; /* If vp == savevp, a no-op */ if (vp != savevp) { if (nfsrv_checkwrongsec(nd, nextop, savevp->v_type)) nd->nd_repstat = nfsvno_testexp(nd, &savevpnes); if (nd->nd_repstat == 0) { - VREF(savevp); + vref(savevp); vrele(vp); vp = savevp; vpnes = savevpnes; cur_fsid = save_fsid; } } if (nd->nd_repstat == 0 && (nd->nd_flag & ND_SAVEDCURSTATEID) != 0) { nd->nd_curstateid = nd->nd_savedcurstateid; nd->nd_flag |= ND_CURSTATEID; } } else { nd->nd_repstat = NFSERR_RESTOREFH; } break; default: /* * Allow a Lookup, Getattr, GetFH, Secinfo on an * non-exported directory if * nfs_rootfhset. Do I need to allow any other Ops? * (You can only have a non-exported vpnes if * nfs_rootfhset is true. See nfsd_fhtovp()) * Allow AUTH_SYS to be used for file systems * exported GSS only for certain Ops, to allow * clients to do mounts more easily. */ if (nfsv4_opflag[op].needscfh && vp) { if (!NFSVNO_EXPORTED(&vpnes) && op != NFSV4OP_LOOKUP && op != NFSV4OP_GETATTR && op != NFSV4OP_GETFH && op != NFSV4OP_ACCESS && op != NFSV4OP_READLINK && op != NFSV4OP_SECINFO && op != NFSV4OP_SECINFONONAME) nd->nd_repstat = NFSERR_NOFILEHANDLE; if (nd->nd_repstat) { if (op == NFSV4OP_SETATTR) { /* * Setattr reply requires a bitmap * even for errors like these. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = 0; } break; } } /* * Save the current positions in the mbuf lists so * that a rollback to this location can be done upon a * redo due to a ERELOOKUP return for a operation. */ mb = nd->nd_mb; bpos = nd->nd_bpos; bextpg = nd->nd_bextpg; bextpgsiz = nd->nd_bextpgsiz; md = nd->nd_md; dpos = nd->nd_dpos; tryagain: if (nfsv4_opflag[op].retfh == 1) { if (!vp) { nd->nd_repstat = NFSERR_NOFILEHANDLE; break; } if (NFSVNO_EXPORTED(&vpnes) && (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP || (op == NFSV4OP_OPEN && vp->v_type == VDIR))) { /* Check for wrong security. */ rstat = nfsvno_testexp(nd, &vpnes); if (rstat != 0) { nd->nd_repstat = rstat; break; } } - VREF(vp); + vref(vp); if (nfsv4_opflag[op].modifyfs) vn_start_write(vp, &temp_mp, V_WAIT); error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp, &nvp, (fhandle_t *)fh.nfsrvfh_data, &vpnes); if (!error && !nd->nd_repstat) { if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) { new_mp = nvp->v_mount; if (fsidcmp(&cur_fsid, &new_mp->mnt_stat.f_fsid) != 0) { /* crossed a server mount point */ nd->nd_repstat = nfsvno_checkexp(new_mp, nd->nd_nam, &nes, &credanon); if (!nd->nd_repstat) nd->nd_repstat = nfsd_excred(nd, &nes, credanon, true); if (credanon != NULL) crfree(credanon); if (!nd->nd_repstat) { vpnes = nes; cur_fsid = new_mp->mnt_stat.f_fsid; } } /* Lookup ops return a locked vnode */ NFSVOPUNLOCK(nvp); } if (!nd->nd_repstat) { vrele(vp); vp = nvp; } else vrele(nvp); } if (nfsv4_opflag[op].modifyfs) vn_finished_write(temp_mp); } else if (nfsv4_opflag[op].retfh == 2) { if (vp == NULL || savevp == NULL) { nd->nd_repstat = NFSERR_NOFILEHANDLE; break; } else if (fsidcmp(&cur_fsid, &save_fsid) != 0) { nd->nd_repstat = NFSERR_XDEV; break; } if (nfsv4_opflag[op].modifyfs) vn_start_write(savevp, &temp_mp, V_WAIT); if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) { - VREF(vp); - VREF(savevp); + vref(vp); + vref(savevp); error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp, vp, &savevpnes, &vpnes); } else nd->nd_repstat = NFSERR_PERM; if (nfsv4_opflag[op].modifyfs) vn_finished_write(temp_mp); } else { if (nfsv4_opflag[op].retfh != 0) panic("nfsrvd_compound"); if (nfsv4_opflag[op].needscfh) { if (vp != NULL) { lktype = nfsv4_opflag[op].lktype; if (nfsv4_opflag[op].modifyfs) { vn_start_write(vp, &temp_mp, V_WAIT); if (op == NFSV4OP_WRITE && MNT_SHARED_WRITES(temp_mp)) lktype = LK_SHARED; } if (NFSVOPLOCK(vp, lktype) == 0) - VREF(vp); + vref(vp); else nd->nd_repstat = NFSERR_PERM; } else { nd->nd_repstat = NFSERR_NOFILEHANDLE; if (op == NFSV4OP_SETATTR) { /* * Setattr reply requires a * bitmap even for errors like * these. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = 0; } break; } if (nd->nd_repstat == 0) { error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp, &vpnes); if ((op == NFSV4OP_SECINFO || op == NFSV4OP_SECINFONONAME) && error == 0 && nd->nd_repstat == 0) { /* * Secinfo and Secinfo_no_name * consume the current FH. */ vrele(vp); vp = NULL; } } if (nfsv4_opflag[op].modifyfs) vn_finished_write(temp_mp); } else { error = (*(nfsrv4_ops0[op]))(nd, isdgram, NULL, &vpnes); } } } if (error) { if (error == EBADRPC || error == NFSERR_BADXDR) { nd->nd_repstat = NFSERR_BADXDR; } else { nd->nd_repstat = error; printf("nfsv4 comperr0=%d\n", error); } error = 0; } if (nd->nd_repstat == ERELOOKUP) { /* * Roll back to the beginning of the operation * arguments. */ nd->nd_md = md; nd->nd_dpos = dpos; /* * Trim off the bogus reply for this operation * and redo the operation. */ nfsm_trimtrailing(nd, mb, bpos, bextpg, bextpgsiz); nd->nd_repstat = 0; nd->nd_flag |= ND_ERELOOKUP; goto tryagain; } nd->nd_flag &= ~ND_ERELOOKUP; if (statsinprog != 0) { nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL, /*then*/ &start_time); statsinprog = 0; } retops++; if (nd->nd_repstat) { *repp = nfsd_errmap(nd); break; } else { *repp = 0; /* NFS4_OK */ } } nfsmout: if (statsinprog != 0) { nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL, /*then*/ &start_time); statsinprog = 0; } if (error) { if (error == EBADRPC || error == NFSERR_BADXDR) nd->nd_repstat = NFSERR_BADXDR; else printf("nfsv4 comperr1=%d\n", error); } if (taglen == -1) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = 0; *tl = 0; } else { *retopsp = txdr_unsigned(retops); } if (vp) vrele(vp); if (savevp) vrele(savevp); if (savecred != NULL) nd->nd_cred = savecred; if (rootcred != NULL) crfree(rootcred); NFSLOCKV4ROOTMUTEX(); nfsv4_relref(&nfsv4rootfs_lock); NFSUNLOCKV4ROOTMUTEX(); NFSEXITCODE2(0, nd); } /* Create a credential for "root". */ static struct ucred * nfsrv_createrootcred(void) { struct ucred *cr; cr = crget(); cr->cr_uid = cr->cr_ruid = cr->cr_svuid = UID_ROOT; crsetgroups_and_egid(cr, 0, NULL, GID_WHEEL); cr->cr_rgid = cr->cr_svgid = cr->cr_gid; cr->cr_prison = curthread->td_ucred->cr_prison; prison_hold(cr->cr_prison); #ifdef MAC mac_cred_associate_nfsd(cr); #endif return (cr); } diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index 8f25a7c4ca70..e9d598014a2f 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/nullfs/null_vnops.c @@ -1,1217 +1,1217 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * John Heidemann of the UCLA Ficus project. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * Ancestors: * ...and... */ /* * Null Layer * * (See mount_nullfs(8) for more information.) * * The null layer duplicates a portion of the filesystem * name space under a new name. In this respect, it is * similar to the loopback filesystem. It differs from * the loopback fs in two respects: it is implemented using * a stackable layers techniques, and its "null-node"s stack above * all lower-layer vnodes, not just over directory vnodes. * * The null layer has two purposes. First, it serves as a demonstration * of layering by proving a layer which does nothing. (It actually * does everything the loopback filesystem does, which is slightly * more than nothing.) Second, the null layer can serve as a prototype * layer. Since it provides all necessary layer framework, * new filesystem layers can be created very easily be starting * with a null layer. * * The remainder of this man page examines the null layer as a basis * for constructing new layers. * * * INSTANTIATING NEW NULL LAYERS * * New null layers are created with mount_nullfs(8). * Mount_nullfs(8) takes two arguments, the pathname * of the lower vfs (target-pn) and the pathname where the null * layer will appear in the namespace (alias-pn). After * the null layer is put into place, the contents * of target-pn subtree will be aliased under alias-pn. * * * OPERATION OF A NULL LAYER * * The null layer is the minimum filesystem layer, * simply bypassing all possible operations to the lower layer * for processing there. The majority of its activity centers * on the bypass routine, through which nearly all vnode operations * pass. * * The bypass routine accepts arbitrary vnode operations for * handling by the lower layer. It begins by examining vnode * operation arguments and replacing any null-nodes by their * lower-layer equivlants. It then invokes the operation * on the lower layer. Finally, it replaces the null-nodes * in the arguments and, if a vnode is return by the operation, * stacks a null-node on top of the returned vnode. * * Although bypass handles most operations, vop_getattr, vop_lock, * vop_unlock, vop_inactive, vop_reclaim, and vop_print are not * bypassed. Vop_getattr must change the fsid being returned. * Vop_lock and vop_unlock must handle any locking for the * current vnode as well as pass the lock request down. * Vop_inactive and vop_reclaim are not bypassed so that * they can handle freeing null-layer specific data. Vop_print * is not bypassed to avoid excessive debugging information. * Also, certain vnode operations change the locking state within * the operation (create, mknod, remove, link, rename, mkdir, rmdir, * and symlink). Ideally these operations should not change the * lock state, but should be changed to let the caller of the * function unlock them. Otherwise all intermediate vnode layers * (such as union, umapfs, etc) must catch these functions to do * the necessary locking at their layer. * * * INSTANTIATING VNODE STACKS * * Mounting associates the null layer with a lower layer, * effect stacking two VFSes. Vnode stacks are instead * created on demand as files are accessed. * * The initial mount creates a single vnode stack for the * root of the new null layer. All other vnode stacks * are created as a result of vnode operations on * this or other null vnode stacks. * * New vnode stacks come into existence as a result of * an operation which returns a vnode. * The bypass routine stacks a null-node above the new * vnode before returning it to the caller. * * For example, imagine mounting a null layer with * "mount_nullfs /usr/include /dev/layer/null". * Changing directory to /dev/layer/null will assign * the root null-node (which was created when the null layer was mounted). * Now consider opening "sys". A vop_lookup would be * done on the root null-node. This operation would bypass through * to the lower layer which would return a vnode representing * the UFS "sys". Null_bypass then builds a null-node * aliasing the UFS "sys" and returns this to the caller. * Later operations on the null-node "sys" will repeat this * process when constructing other vnode stacks. * * * CREATING OTHER FILE SYSTEM LAYERS * * One of the easiest ways to construct new filesystem layers is to make * a copy of the null layer, rename all files and variables, and * then begin modifing the copy. Sed can be used to easily rename * all variables. * * The umap layer is an example of a layer descended from the * null layer. * * * INVOKING OPERATIONS ON LOWER LAYERS * * There are two techniques to invoke operations on a lower layer * when the operation cannot be completely bypassed. Each method * is appropriate in different situations. In both cases, * it is the responsibility of the aliasing layer to make * the operation arguments "correct" for the lower layer * by mapping a vnode arguments to the lower layer. * * The first approach is to call the aliasing layer's bypass routine. * This method is most suitable when you wish to invoke the operation * currently being handled on the lower layer. It has the advantage * that the bypass routine already must do argument mapping. * An example of this is null_getattrs in the null layer. * * A second approach is to directly invoke vnode operations on * the lower layer with the VOP_OPERATIONNAME interface. * The advantage of this method is that it is easy to invoke * arbitrary operations on the lower layer. The disadvantage * is that vnode arguments must be manualy mapped. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW, &null_bug_bypass, 0, ""); /* * Synchronize inotify flags with the lower vnode: * - If the upper vnode has the flag set and the lower does not, then the lower * vnode is unwatched and the upper vnode does not need to go through * VOP_INOTIFY. * - If the lower vnode is watched, then the upper vnode should go through * VOP_INOTIFY, so copy the flag up. */ static void null_copy_inotify(struct vnode *vp, struct vnode *lvp, short flag) { if ((vn_irflag_read(vp) & flag) != 0) { if (__predict_false((vn_irflag_read(lvp) & flag) == 0)) vn_irflag_unset(vp, flag); } else if ((vn_irflag_read(lvp) & flag) != 0) { if (__predict_false((vn_irflag_read(vp) & flag) == 0)) vn_irflag_set(vp, flag); } } /* * This is the 10-Apr-92 bypass routine. * This version has been optimized for speed, throwing away some * safety checks. It should still always work, but it's not as * robust to programmer errors. * * In general, we map all vnodes going down and unmap them on the way back. * As an exception to this, vnodes can be marked "unmapped" by setting * the Nth bit in operation's vdesc_flags. * * Also, some BSD vnode operations have the side effect of vrele'ing * their arguments. With stacking, the reference counts are held * by the upper node, not the lower one, so we must handle these * side-effects here. This is not of concern in Sun-derived systems * since there are no such side-effects. * * This makes the following assumptions: * - only one returned vpp * - no INOUT vpp's (Sun's vop_open has one of these) * - the vnode operation vector of the first vnode should be used * to determine what implementation of the op should be invoked * - all mapped vnodes are of our vnode-type (NEEDSWORK: * problems on rmdir'ing mount points and renaming?) */ int null_bypass(struct vop_generic_args *ap) { struct vnode **this_vp_p; struct vnode *old_vps[VDESC_MAX_VPS]; struct vnode **vps_p[VDESC_MAX_VPS]; struct vnode ***vppp; struct vnode *lvp; struct vnodeop_desc *descp = ap->a_desc; int error, i, reles; if (null_bug_bypass) printf ("null_bypass: %s\n", descp->vdesc_name); #ifdef DIAGNOSTIC /* * We require at least one vp. */ if (descp->vdesc_vp_offsets == NULL || descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) panic ("null_bypass: no vp's in map"); #endif /* * Map the vnodes going in. * Later, we'll invoke the operation based on * the first mapped vnode's operation vector. */ reles = descp->vdesc_flags; for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) break; /* bail out at end of list */ vps_p[i] = this_vp_p = VOPARG_OFFSETTO(struct vnode **, descp->vdesc_vp_offsets[i], ap); /* * We're not guaranteed that any but the first vnode * are of our type. Check for and don't map any * that aren't. (We must always map first vp or vclean fails.) */ if (i != 0 && (*this_vp_p == NULL || (*this_vp_p)->v_op != &null_vnodeops)) { old_vps[i] = NULL; } else { old_vps[i] = *this_vp_p; *(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p); /* * The upper vnode reference to the lower * vnode is the only reference that keeps our * pointer to the lower vnode alive. If lower * vnode is relocked during the VOP call, * upper vnode might become unlocked and * reclaimed, which invalidates our reference. * Add a transient hold around VOP call. */ vhold(*this_vp_p); /* * XXX - Several operations have the side effect * of vrele'ing their vp's. We must account for * that. (This should go away in the future.) */ if (reles & VDESC_VP0_WILLRELE) vref(*this_vp_p); } } /* * Call the operation on the lower layer * with the modified argument structure. */ if (vps_p[0] != NULL && *vps_p[0] != NULL) { error = ap->a_desc->vdesc_call(ap); } else { printf("null_bypass: no map for %s\n", descp->vdesc_name); error = EINVAL; } /* * Maintain the illusion of call-by-value * by restoring vnodes in the argument structure * to their original value. */ reles = descp->vdesc_flags; for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) break; /* bail out at end of list */ if (old_vps[i] != NULL) { lvp = *(vps_p[i]); /* * Get rid of the transient hold on lvp. Copy inotify * flags up in case something is watching the lower * layer. * * If lowervp was unlocked during VOP * operation, nullfs upper vnode could have * been reclaimed, which changes its v_vnlock * back to private v_lock. In this case we * must move lock ownership from lower to * upper (reclaimed) vnode. */ if (lvp != NULL) { null_copy_inotify(old_vps[i], lvp, VIRF_INOTIFY); null_copy_inotify(old_vps[i], lvp, VIRF_INOTIFY_PARENT); if (VOP_ISLOCKED(lvp) == LK_EXCLUSIVE && old_vps[i]->v_vnlock != lvp->v_vnlock) { VOP_UNLOCK(lvp); VOP_LOCK(old_vps[i], LK_EXCLUSIVE | LK_RETRY); } vdrop(lvp); } *(vps_p[i]) = old_vps[i]; #if 0 if (reles & VDESC_VP0_WILLUNLOCK) VOP_UNLOCK(*(vps_p[i]), 0); #endif if (reles & VDESC_VP0_WILLRELE) vrele(*(vps_p[i])); } } /* * Map the possible out-going vpp * (Assumes that the lower layer always returns * a VREF'ed vpp unless it gets an error.) */ if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && error == 0) { /* * XXX - even though some ops have vpp returned vp's, * several ops actually vrele this before returning. * We must avoid these ops. * (This should go away when these ops are regularized.) */ vppp = VOPARG_OFFSETTO(struct vnode ***, descp->vdesc_vpp_offset, ap); if (*vppp != NULL) error = null_nodeget(old_vps[0]->v_mount, **vppp, *vppp); } return (error); } static int null_add_writecount(struct vop_add_writecount_args *ap) { struct vnode *lvp, *vp; int error; vp = ap->a_vp; lvp = NULLVPTOLOWERVP(vp); VI_LOCK(vp); /* text refs are bypassed to lowervp */ VNASSERT(vp->v_writecount >= 0, vp, ("wrong null writecount")); VNASSERT(vp->v_writecount + ap->a_inc >= 0, vp, ("wrong writecount inc %d", ap->a_inc)); error = VOP_ADD_WRITECOUNT(lvp, ap->a_inc); if (error == 0) vp->v_writecount += ap->a_inc; VI_UNLOCK(vp); return (error); } /* * We have to carry on the locking protocol on the null layer vnodes * as we progress through the tree. We also have to enforce read-only * if this layer is mounted read-only. */ static int null_lookup(struct vop_lookup_args *ap) { struct componentname *cnp = ap->a_cnp; struct vnode *dvp = ap->a_dvp; uint64_t flags = cnp->cn_flags; struct vnode *vp, *ldvp, *lvp; struct mount *mp; int error; mp = dvp->v_mount; if ((flags & ISLASTCN) != 0 && (mp->mnt_flag & MNT_RDONLY) != 0 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); /* * Although it is possible to call null_bypass(), we'll do * a direct call to reduce overhead */ ldvp = NULLVPTOLOWERVP(dvp); vp = lvp = NULL; /* * Renames in the lower mounts might create an inconsistent * configuration where lower vnode is moved out of the directory tree * remounted by our null mount. * * Do not try to handle it fancy, just avoid VOP_LOOKUP() with DOTDOT * name which cannot be handled by the VOP. */ if ((flags & ISDOTDOT) != 0) { struct nameidata *ndp; if ((ldvp->v_vflag & VV_ROOT) != 0) { KASSERT((dvp->v_vflag & VV_ROOT) == 0, ("ldvp %p fl %#x dvp %p fl %#x flags %#jx", ldvp, ldvp->v_vflag, dvp, dvp->v_vflag, (uintmax_t)flags)); return (ENOENT); } ndp = vfs_lookup_nameidata(cnp); if (ndp != NULL && vfs_lookup_isroot(ndp, ldvp)) return (ENOENT); } /* * Hold ldvp. The reference on it, owned by dvp, is lost in * case of dvp reclamation, and we need ldvp to move our lock * from ldvp to dvp. */ vhold(ldvp); error = VOP_LOOKUP(ldvp, &lvp, cnp); /* * VOP_LOOKUP() on lower vnode may unlock ldvp, which allows * dvp to be reclaimed due to shared v_vnlock. Check for the * doomed state and return error. */ if (VN_IS_DOOMED(dvp)) { if (error == 0 || error == EJUSTRETURN) { if (lvp != NULL) vput(lvp); error = ENOENT; } /* * If vgone() did reclaimed dvp before curthread * relocked ldvp, the locks of dvp and ldpv are no * longer shared. In this case, relock of ldvp in * lower fs VOP_LOOKUP() does not restore the locking * state of dvp. Compensate for this by unlocking * ldvp and locking dvp, which is also correct if the * locks are still shared. */ VOP_UNLOCK(ldvp); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); } vdrop(ldvp); if (error == EJUSTRETURN && (flags & ISLASTCN) != 0 && (mp->mnt_flag & MNT_RDONLY) != 0 && (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) error = EROFS; if ((error == 0 || error == EJUSTRETURN) && lvp != NULL) { if (ldvp == lvp) { *ap->a_vpp = dvp; - VREF(dvp); + vref(dvp); vrele(lvp); } else { error = null_nodeget(mp, lvp, &vp); if (error == 0) *ap->a_vpp = vp; } } return (error); } static int null_open(struct vop_open_args *ap) { int retval; struct vnode *vp, *ldvp; vp = ap->a_vp; ldvp = NULLVPTOLOWERVP(vp); retval = null_bypass(&ap->a_gen); if (retval == 0) { vp->v_object = ldvp->v_object; if ((vn_irflag_read(ldvp) & VIRF_PGREAD) != 0) { MPASS(vp->v_object != NULL); if ((vn_irflag_read(vp) & VIRF_PGREAD) == 0) { vn_irflag_set_cond(vp, VIRF_PGREAD); } } } return (retval); } /* * Setattr call. Disallow write attempts if the layer is mounted read-only. */ static int null_setattr(struct vop_setattr_args *ap) { struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && (vp->v_mount->mnt_flag & MNT_RDONLY)) return (EROFS); if (vap->va_size != VNOVAL) { switch (vp->v_type) { case VDIR: return (EISDIR); case VCHR: case VBLK: case VSOCK: case VFIFO: if (vap->va_flags != VNOVAL) return (EOPNOTSUPP); return (0); case VREG: case VLNK: default: /* * Disallow write attempts if the filesystem is * mounted read-only. */ if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); } } return (null_bypass(&ap->a_gen)); } /* * We handle stat and getattr only to change the fsid. */ static int null_stat(struct vop_stat_args *ap) { int error; if ((error = null_bypass(&ap->a_gen)) != 0) return (error); ap->a_sb->st_dev = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; return (0); } static int null_getattr(struct vop_getattr_args *ap) { int error; if ((error = null_bypass(&ap->a_gen)) != 0) return (error); ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; return (0); } /* * Handle to disallow write access if mounted read-only. */ static int null_access(struct vop_access_args *ap) { struct vnode *vp = ap->a_vp; accmode_t accmode = ap->a_accmode; /* * Disallow write attempts on read-only layers; * unless the file is a socket, fifo, or a block or * character device resident on the filesystem. */ if (accmode & VWRITE) { switch (vp->v_type) { case VDIR: case VLNK: case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; default: break; } } return (null_bypass(&ap->a_gen)); } static int null_accessx(struct vop_accessx_args *ap) { struct vnode *vp = ap->a_vp; accmode_t accmode = ap->a_accmode; /* * Disallow write attempts on read-only layers; * unless the file is a socket, fifo, or a block or * character device resident on the filesystem. */ if (accmode & VWRITE) { switch (vp->v_type) { case VDIR: case VLNK: case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; default: break; } } return (null_bypass(&ap->a_gen)); } /* * Increasing refcount of lower vnode is needed at least for the case * when lower FS is NFS to do sillyrename if the file is in use. * Unfortunately v_usecount is incremented in many places in * the kernel and, as such, there may be races that result in * the NFS client doing an extraneous silly rename, but that seems * preferable to not doing a silly rename when it is needed. */ static int null_remove(struct vop_remove_args *ap) { int retval, vreleit; struct vnode *lvp, *vp; vp = ap->a_vp; if (vrefcnt(vp) > 1) { lvp = NULLVPTOLOWERVP(vp); - VREF(lvp); + vref(lvp); vreleit = 1; } else vreleit = 0; VTONULL(vp)->null_flags |= NULLV_DROP; retval = null_bypass(&ap->a_gen); if (vreleit != 0) vrele(lvp); return (retval); } /* * We handle this to eliminate null FS to lower FS * file moving. Don't know why we don't allow this, * possibly we should. */ static int null_rename(struct vop_rename_args *ap) { struct vnode *fdvp, *fvp, *tdvp, *tvp; struct vnode *lfdvp, *lfvp, *ltdvp, *ltvp; struct null_node *fdnn, *fnn, *tdnn, *tnn; int error; tdvp = ap->a_tdvp; fvp = ap->a_fvp; fdvp = ap->a_fdvp; tvp = ap->a_tvp; lfdvp = NULL; /* Check for cross-device rename. */ if ((fvp->v_mount != tdvp->v_mount) || (tvp != NULL && fvp->v_mount != tvp->v_mount)) { error = EXDEV; goto upper_err; } VI_LOCK(fdvp); fdnn = VTONULL(fdvp); if (fdnn == NULL) { /* fdvp is not locked, can be doomed */ VI_UNLOCK(fdvp); error = ENOENT; goto upper_err; } lfdvp = fdnn->null_lowervp; vref(lfdvp); VI_UNLOCK(fdvp); VI_LOCK(fvp); fnn = VTONULL(fvp); if (fnn == NULL) { VI_UNLOCK(fvp); error = ENOENT; goto upper_err; } lfvp = fnn->null_lowervp; vref(lfvp); VI_UNLOCK(fvp); tdnn = VTONULL(tdvp); ltdvp = tdnn->null_lowervp; vref(ltdvp); if (tvp != NULL) { tnn = VTONULL(tvp); ltvp = tnn->null_lowervp; vref(ltvp); tnn->null_flags |= NULLV_DROP; } else { ltvp = NULL; } error = VOP_RENAME(lfdvp, lfvp, ap->a_fcnp, ltdvp, ltvp, ap->a_tcnp); vrele(fdvp); vrele(fvp); vrele(tdvp); if (tvp != NULL) vrele(tvp); return (error); upper_err: if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp) vput(tvp); if (lfdvp != NULL) vrele(lfdvp); vrele(fdvp); vrele(fvp); return (error); } static int null_rmdir(struct vop_rmdir_args *ap) { VTONULL(ap->a_vp)->null_flags |= NULLV_DROP; return (null_bypass(&ap->a_gen)); } /* * We need to process our own vnode lock and then clear the * interlock flag as it applies only to our vnode, not the * vnodes below us on the stack. */ static int null_lock(struct vop_lock1_args *ap) { struct vnode *vp = ap->a_vp; int flags; struct null_node *nn; struct vnode *lvp; int error; if ((ap->a_flags & LK_INTERLOCK) == 0) VI_LOCK(vp); else ap->a_flags &= ~LK_INTERLOCK; flags = ap->a_flags; nn = VTONULL(vp); /* * If we're still active we must ask the lower layer to * lock as ffs has special lock considerations in its * vop lock. */ if (nn != NULL && (lvp = NULLVPTOLOWERVP(vp)) != NULL) { /* * We have to hold the vnode here to solve a potential * reclaim race. If we're forcibly vgone'd while we * still have refs, a thread could be sleeping inside * the lowervp's vop_lock routine. When we vgone we will * drop our last ref to the lowervp, which would allow it * to be reclaimed. The lowervp could then be recycled, * in which case it is not legal to be sleeping in its VOP. * We prevent it from being recycled by holding the vnode * here. */ vholdnz(lvp); VI_UNLOCK(vp); error = VOP_LOCK(lvp, flags); /* * We might have slept to get the lock and someone might have * clean our vnode already, switching vnode lock from one in * lowervp to v_lock in our own vnode structure. Handle this * case by reacquiring correct lock in requested mode. */ if (VTONULL(vp) == NULL && error == 0) { ap->a_flags &= ~LK_TYPE_MASK; switch (flags & LK_TYPE_MASK) { case LK_SHARED: ap->a_flags |= LK_SHARED; break; case LK_UPGRADE: case LK_EXCLUSIVE: ap->a_flags |= LK_EXCLUSIVE; break; default: panic("Unsupported lock request %d\n", ap->a_flags); } VOP_UNLOCK(lvp); error = vop_stdlock(ap); } vdrop(lvp); } else { VI_UNLOCK(vp); error = vop_stdlock(ap); } return (error); } /* * We need to process our own vnode unlock and then clear the * interlock flag as it applies only to our vnode, not the * vnodes below us on the stack. */ static int null_unlock(struct vop_unlock_args *ap) { struct vnode *vp = ap->a_vp; struct null_node *nn; struct vnode *lvp; int error; nn = VTONULL(vp); if (nn != NULL && (lvp = NULLVPTOLOWERVP(vp)) != NULL) { vholdnz(lvp); error = VOP_UNLOCK(lvp); vdrop(lvp); } else { error = vop_stdunlock(ap); } return (error); } /* * Do not allow the VOP_INACTIVE to be passed to the lower layer, * since the reference count on the lower vnode is not related to * ours. */ static int null_want_recycle(struct vnode *vp) { struct vnode *lvp; struct null_node *xp; struct mount *mp; struct null_mount *xmp; xp = VTONULL(vp); lvp = NULLVPTOLOWERVP(vp); mp = vp->v_mount; xmp = MOUNTTONULLMOUNT(mp); if ((xmp->nullm_flags & NULLM_CACHE) == 0 || (xp->null_flags & NULLV_DROP) != 0 || (lvp->v_vflag & VV_NOSYNC) != 0) { /* * If this is the last reference and caching of the * nullfs vnodes is not enabled, or the lower vnode is * deleted, then free up the vnode so as not to tie up * the lower vnodes. */ return (1); } return (0); } static int null_inactive(struct vop_inactive_args *ap) { struct vnode *vp; vp = ap->a_vp; if (null_want_recycle(vp)) { vp->v_object = NULL; vrecycle(vp); } return (0); } static int null_need_inactive(struct vop_need_inactive_args *ap) { return (null_want_recycle(ap->a_vp) || vn_need_pageq_flush(ap->a_vp)); } /* * Now, the nullfs vnode and, due to the sharing lock, the lower * vnode, are exclusively locked, and we shall destroy the null vnode. */ static int null_reclaim(struct vop_reclaim_args *ap) { struct vnode *vp; struct null_node *xp; struct vnode *lowervp; vp = ap->a_vp; xp = VTONULL(vp); lowervp = xp->null_lowervp; KASSERT(lowervp != NULL && vp->v_vnlock != &vp->v_lock, ("Reclaiming incomplete null vnode %p", vp)); null_hashrem(xp); /* * Use the interlock to protect the clearing of v_data to * prevent faults in null_lock(). */ lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL); VI_LOCK(vp); vp->v_data = NULL; vp->v_object = NULL; vp->v_vnlock = &vp->v_lock; /* * If we were opened for write, we leased the write reference * to the lower vnode. If this is a reclamation due to the * forced unmount, undo the reference now. */ if (vp->v_writecount > 0) VOP_ADD_WRITECOUNT(lowervp, -vp->v_writecount); else if (vp->v_writecount < 0) vp->v_writecount = 0; VI_UNLOCK(vp); if ((xp->null_flags & NULLV_NOUNLOCK) != 0) vunref(lowervp); else vput(lowervp); free(xp, M_NULLFSNODE); return (0); } static int null_print(struct vop_print_args *ap) { struct vnode *vp = ap->a_vp; printf("\tvp=%p, lowervp=%p\n", vp, VTONULL(vp)->null_lowervp); return (0); } /* ARGSUSED */ static int null_getwritemount(struct vop_getwritemount_args *ap) { struct null_node *xp; struct vnode *lowervp; struct vnode *vp; vp = ap->a_vp; VI_LOCK(vp); xp = VTONULL(vp); if (xp && (lowervp = xp->null_lowervp)) { vholdnz(lowervp); VI_UNLOCK(vp); VOP_GETWRITEMOUNT(lowervp, ap->a_mpp); vdrop(lowervp); } else { VI_UNLOCK(vp); *(ap->a_mpp) = NULL; } return (0); } static int null_vptofh(struct vop_vptofh_args *ap) { struct vnode *lvp; lvp = NULLVPTOLOWERVP(ap->a_vp); return VOP_VPTOFH(lvp, ap->a_fhp); } static int null_vptocnp(struct vop_vptocnp_args *ap) { struct vnode *vp = ap->a_vp; struct vnode **dvp = ap->a_vpp; struct vnode *lvp, *ldvp; struct mount *mp; int error, locked; locked = VOP_ISLOCKED(vp); lvp = NULLVPTOLOWERVP(vp); mp = vp->v_mount; error = vfs_busy(mp, MBF_NOWAIT); if (error != 0) return (error); vhold(lvp); VOP_UNLOCK(vp); /* vp is held by vn_vptocnp_locked that called us */ ldvp = lvp; vref(lvp); error = vn_vptocnp(&ldvp, ap->a_buf, ap->a_buflen); vdrop(lvp); if (error != 0) { vn_lock(vp, locked | LK_RETRY); vfs_unbusy(mp); return (ENOENT); } error = vn_lock(ldvp, LK_SHARED); if (error != 0) { vrele(ldvp); vn_lock(vp, locked | LK_RETRY); vfs_unbusy(mp); return (ENOENT); } error = null_nodeget(mp, ldvp, dvp); if (error == 0) { #ifdef DIAGNOSTIC NULLVPTOLOWERVP(*dvp); #endif VOP_UNLOCK(*dvp); /* keep reference on *dvp */ } vn_lock(vp, locked | LK_RETRY); vfs_unbusy(mp); return (error); } static int null_read_pgcache(struct vop_read_pgcache_args *ap) { struct vnode *lvp, *vp; struct null_node *xp; int error; vp = ap->a_vp; VI_LOCK(vp); xp = VTONULL(vp); if (xp == NULL) { VI_UNLOCK(vp); return (EJUSTRETURN); } lvp = xp->null_lowervp; vref(lvp); VI_UNLOCK(vp); error = VOP_READ_PGCACHE(lvp, ap->a_uio, ap->a_ioflag, ap->a_cred); vrele(lvp); return (error); } static int null_advlock(struct vop_advlock_args *ap) { struct vnode *lvp, *vp; struct null_node *xp; int error; vp = ap->a_vp; VI_LOCK(vp); xp = VTONULL(vp); if (xp == NULL) { VI_UNLOCK(vp); return (EBADF); } lvp = xp->null_lowervp; vref(lvp); VI_UNLOCK(vp); error = VOP_ADVLOCK(lvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); vrele(lvp); return (error); } /* * Avoid standard bypass, since lower dvp and vp could be no longer * valid after vput(). */ static int null_vput_pair(struct vop_vput_pair_args *ap) { struct mount *mp; struct vnode *dvp, *ldvp, *lvp, *vp, *vp1, **vpp; int error, res; dvp = ap->a_dvp; ldvp = NULLVPTOLOWERVP(dvp); vref(ldvp); vpp = ap->a_vpp; vp = NULL; lvp = NULL; mp = NULL; if (vpp != NULL) vp = *vpp; if (vp != NULL) { lvp = NULLVPTOLOWERVP(vp); vref(lvp); if (!ap->a_unlock_vp) { vhold(vp); vhold(lvp); mp = vp->v_mount; vfs_ref(mp); } } res = VOP_VPUT_PAIR(ldvp, lvp != NULL ? &lvp : NULL, true); if (vp != NULL && ap->a_unlock_vp) vrele(vp); vrele(dvp); if (vp == NULL || ap->a_unlock_vp) return (res); /* lvp has been unlocked and vp might be reclaimed */ VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY); if (vp->v_data == NULL && vfs_busy(mp, MBF_NOWAIT) == 0) { vput(vp); vget(lvp, LK_EXCLUSIVE | LK_RETRY); if (VN_IS_DOOMED(lvp)) { vput(lvp); vget(vp, LK_EXCLUSIVE | LK_RETRY); } else { error = null_nodeget(mp, lvp, &vp1); if (error == 0) { *vpp = vp1; } else { vget(vp, LK_EXCLUSIVE | LK_RETRY); } } vfs_unbusy(mp); } vdrop(lvp); vdrop(vp); vfs_rel(mp); return (res); } static int null_getlowvnode(struct vop_getlowvnode_args *ap) { struct vnode *vp, *vpl; vp = ap->a_vp; if (vn_lock(vp, LK_SHARED) != 0) return (EBADF); vpl = NULLVPTOLOWERVP(vp); vhold(vpl); VOP_UNLOCK(vp); VOP_GETLOWVNODE(vpl, ap->a_vplp, ap->a_flags); vdrop(vpl); return (0); } /* * Global vfs data structures */ struct vop_vector null_vnodeops = { .vop_bypass = null_bypass, .vop_access = null_access, .vop_accessx = null_accessx, .vop_advlock = null_advlock, .vop_advlockpurge = vop_stdadvlockpurge, .vop_bmap = VOP_EOPNOTSUPP, .vop_stat = null_stat, .vop_getattr = null_getattr, .vop_getlowvnode = null_getlowvnode, .vop_getwritemount = null_getwritemount, .vop_inactive = null_inactive, .vop_need_inactive = null_need_inactive, .vop_islocked = vop_stdislocked, .vop_lock1 = null_lock, .vop_lookup = null_lookup, .vop_open = null_open, .vop_print = null_print, .vop_read_pgcache = null_read_pgcache, .vop_reclaim = null_reclaim, .vop_remove = null_remove, .vop_rename = null_rename, .vop_rmdir = null_rmdir, .vop_setattr = null_setattr, .vop_strategy = VOP_EOPNOTSUPP, .vop_unlock = null_unlock, .vop_vptocnp = null_vptocnp, .vop_vptofh = null_vptofh, .vop_add_writecount = null_add_writecount, .vop_vput_pair = null_vput_pair, .vop_copy_file_range = VOP_PANIC, }; VFS_VOP_VECTOR_REGISTER(null_vnodeops); diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c index 8cd092118d0e..a30b5e4f551d 100644 --- a/sys/fs/pseudofs/pseudofs_vnops.c +++ b/sys/fs/pseudofs/pseudofs_vnops.c @@ -1,1166 +1,1166 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2001 Dag-Erling Smørgrav * All rights reserved. * * 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 * in this position and unchanged. * 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 #include "opt_pseudofs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define KASSERT_PN_IS_DIR(pn) \ KASSERT((pn)->pn_type == pfstype_root || \ (pn)->pn_type == pfstype_dir || \ (pn)->pn_type == pfstype_procdir, \ ("%s(): VDIR vnode refers to non-directory pfs_node", __func__)) #define KASSERT_PN_IS_FILE(pn) \ KASSERT((pn)->pn_type == pfstype_file, \ ("%s(): VREG vnode refers to non-file pfs_node", __func__)) #define KASSERT_PN_IS_LINK(pn) \ KASSERT((pn)->pn_type == pfstype_symlink, \ ("%s(): VLNK vnode refers to non-link pfs_node", __func__)) #define PFS_MAXBUFSIZ 1024 * 1024 /* * Returns the fileno, adjusted for target pid */ static uint32_t pn_fileno(struct pfs_node *pn, pid_t pid) { KASSERT(pn->pn_fileno > 0, ("%s(): no fileno allocated", __func__)); if (pid != NO_PID) return (pn->pn_fileno * NO_PID + pid); return (pn->pn_fileno); } /* * Returns non-zero if given file is visible to given thread. */ static int pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc) { if (proc == NULL) return (0); PROC_LOCK_ASSERT(proc, MA_OWNED); if ((proc->p_flag & P_WEXIT) != 0) return (0); if (p_cansee(td, proc) != 0) return (0); return (pn_vis(td, proc, pn)); } static int pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid, struct proc **p) { struct proc *proc; PFS_TRACE(("%s (pid: %d, req: %d)", pn->pn_name, pid, td->td_proc->p_pid)); if (p) *p = NULL; if (pid == NO_PID) PFS_RETURN (pn_vis(td, NULL, pn)); proc = pfind(pid); if (proc == NULL) PFS_RETURN (0); if (pfs_visible_proc(td, pn, proc)) { if (p) *p = proc; else PROC_UNLOCK(proc); PFS_RETURN (1); } PROC_UNLOCK(proc); PFS_RETURN (0); } static int pfs_lookup_proc(pid_t pid, struct proc **p) { struct proc *proc; proc = pfind(pid); if (proc == NULL) return (0); if ((proc->p_flag & P_WEXIT) != 0) { PROC_UNLOCK(proc); return (0); } _PHOLD(proc); PROC_UNLOCK(proc); *p = proc; return (1); } /* * Verify permissions */ static int pfs_access(struct vop_access_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct vattr vattr; int error; PFS_TRACE(("%s", pvd->pvd_pn->pn_name)); (void)pvd; error = VOP_GETATTR(vn, &vattr, va->a_cred); if (error) PFS_RETURN (error); error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, vattr.va_gid, va->a_accmode, va->a_cred); PFS_RETURN (error); } /* * Close a file or directory */ static int pfs_close(struct vop_close_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; struct proc *proc; int error; PFS_TRACE(("%s", pn->pn_name)); pfs_assert_not_owned(pn); /* * Do nothing unless this is the last close and the node has a * last-close handler. */ if (vrefcnt(vn) > 1 || pn->pn_close == NULL) PFS_RETURN (0); if (pvd->pvd_pid != NO_PID) { proc = pfind(pvd->pvd_pid); } else { proc = NULL; } error = pn_close(va->a_td, proc, pn); if (proc != NULL) PROC_UNLOCK(proc); PFS_RETURN (error); } /* * Get file attributes */ static int pfs_getattr(struct vop_getattr_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; struct vattr *vap = va->a_vap; struct proc *proc; int error = 0; PFS_TRACE(("%s", pn->pn_name)); pfs_assert_not_owned(pn); if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) PFS_RETURN (ENOENT); vap->va_type = vn->v_type; vap->va_fileid = pn_fileno(pn, pvd->pvd_pid); vap->va_flags = 0; vap->va_blocksize = PAGE_SIZE; vap->va_bytes = vap->va_size = 0; vap->va_filerev = 0; vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0]; vap->va_nlink = 1; nanotime(&vap->va_ctime); vap->va_atime = vap->va_mtime = vap->va_ctime; switch (pn->pn_type) { case pfstype_procdir: case pfstype_root: case pfstype_dir: #if 0 pfs_lock(pn); /* compute link count */ pfs_unlock(pn); #endif vap->va_mode = 0555; break; case pfstype_file: case pfstype_symlink: vap->va_mode = 0444; break; default: printf("shouldn't be here!\n"); vap->va_mode = 0; break; } if (proc != NULL) { vap->va_uid = proc->p_ucred->cr_ruid; vap->va_gid = proc->p_ucred->cr_rgid; } else { vap->va_uid = 0; vap->va_gid = 0; } if (pn->pn_attr != NULL) error = pn_attr(curthread, proc, pn, vap); if(proc != NULL) PROC_UNLOCK(proc); PFS_RETURN (error); } /* * Perform an ioctl */ static int pfs_ioctl(struct vop_ioctl_args *va) { struct vnode *vn; struct pfs_vdata *pvd; struct pfs_node *pn; struct proc *proc; int error; vn = va->a_vp; vn_lock(vn, LK_SHARED | LK_RETRY); if (VN_IS_DOOMED(vn)) { VOP_UNLOCK(vn); return (EBADF); } pvd = vn->v_data; pn = pvd->pvd_pn; PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command)); pfs_assert_not_owned(pn); if (vn->v_type != VREG) { VOP_UNLOCK(vn); PFS_RETURN (EINVAL); } KASSERT_PN_IS_FILE(pn); if (pn->pn_ioctl == NULL) { VOP_UNLOCK(vn); PFS_RETURN (ENOTTY); } /* * This is necessary because process' privileges may * have changed since the open() call. */ if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) { VOP_UNLOCK(vn); PFS_RETURN (EIO); } error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data); if (proc != NULL) PROC_UNLOCK(proc); VOP_UNLOCK(vn); PFS_RETURN (error); } /* * Perform getextattr */ static int pfs_getextattr(struct vop_getextattr_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; struct proc *proc; int error; PFS_TRACE(("%s", pn->pn_name)); pfs_assert_not_owned(pn); /* * This is necessary because either process' privileges may * have changed since the open() call. */ if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) PFS_RETURN (EIO); if (pn->pn_getextattr == NULL) error = EOPNOTSUPP; else error = pn_getextattr(curthread, proc, pn, va->a_attrnamespace, va->a_name, va->a_uio, va->a_size, va->a_cred); if (proc != NULL) PROC_UNLOCK(proc); PFS_RETURN (error); } /* * Convert a vnode to its component name */ static int pfs_vptocnp(struct vop_vptocnp_args *ap) { struct vnode *vp = ap->a_vp; struct vnode **dvp = ap->a_vpp; struct pfs_vdata *pvd = vp->v_data; struct pfs_node *pd = pvd->pvd_pn; struct pfs_node *pn; struct mount *mp; char *buf = ap->a_buf; size_t *buflen = ap->a_buflen; char pidbuf[PFS_NAMELEN]; pid_t pid = pvd->pvd_pid; int len, i, error, locked; i = *buflen; error = 0; pfs_lock(pd); if (vp->v_type == VDIR && pd->pn_type == pfstype_root) { *dvp = vp; vhold(*dvp); pfs_unlock(pd); PFS_RETURN (0); } else if (vp->v_type == VDIR && pd->pn_type == pfstype_procdir) { len = snprintf(pidbuf, sizeof(pidbuf), "%d", pid); i -= len; if (i < 0) { error = ENOMEM; goto failed; } bcopy(pidbuf, buf + i, len); } else { len = strlen(pd->pn_name); i -= len; if (i < 0) { error = ENOMEM; goto failed; } bcopy(pd->pn_name, buf + i, len); } pn = pd->pn_parent; pfs_unlock(pd); mp = vp->v_mount; error = vfs_busy(mp, 0); if (error) return (error); /* * vp is held by caller. */ locked = VOP_ISLOCKED(vp); VOP_UNLOCK(vp); error = pfs_vncache_alloc(mp, dvp, pn, pid); if (error) { vn_lock(vp, locked | LK_RETRY); vfs_unbusy(mp); PFS_RETURN(error); } *buflen = i; VOP_UNLOCK(*dvp); vn_lock(vp, locked | LK_RETRY); vfs_unbusy(mp); PFS_RETURN (0); failed: pfs_unlock(pd); PFS_RETURN(error); } /* * Look up a file or directory */ static int pfs_lookup(struct vop_cachedlookup_args *va) { struct vnode *vn = va->a_dvp; struct vnode **vpp = va->a_vpp; struct componentname *cnp = va->a_cnp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pd = pvd->pvd_pn; struct pfs_node *pn, *pdn = NULL; struct mount *mp; pid_t pid = pvd->pvd_pid; char *pname; int error, i, namelen, visible; PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr)); pfs_assert_not_owned(pd); if (vn->v_type != VDIR) PFS_RETURN (ENOTDIR); KASSERT_PN_IS_DIR(pd); /* * Don't support DELETE or RENAME. CREATE is supported so * that O_CREAT will work, but the lookup will still fail if * the file does not exist. */ if ((cnp->cn_flags & ISLASTCN) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) PFS_RETURN (EOPNOTSUPP); /* shortcut: check if the name is too long */ if (cnp->cn_namelen >= PFS_NAMELEN) PFS_RETURN (ENOENT); /* check that parent directory is visible... */ if (!pfs_visible(curthread, pd, pvd->pvd_pid, NULL)) PFS_RETURN (ENOENT); /* self */ namelen = cnp->cn_namelen; pname = cnp->cn_nameptr; if (namelen == 1 && pname[0] == '.') { pn = pd; *vpp = vn; - VREF(vn); + vref(vn); PFS_RETURN (0); } mp = vn->v_mount; /* parent */ if (cnp->cn_flags & ISDOTDOT) { if (pd->pn_type == pfstype_root) PFS_RETURN (EIO); error = vfs_busy(mp, MBF_NOWAIT); if (error != 0) { vfs_ref(mp); VOP_UNLOCK(vn); error = vfs_busy(mp, 0); vn_lock(vn, LK_EXCLUSIVE | LK_RETRY); vfs_rel(mp); if (error != 0) PFS_RETURN(ENOENT); if (VN_IS_DOOMED(vn)) { vfs_unbusy(mp); PFS_RETURN(ENOENT); } } VOP_UNLOCK(vn); KASSERT(pd->pn_parent != NULL, ("%s(): non-root directory has no parent", __func__)); /* * This one is tricky. Descendents of procdir nodes * inherit their parent's process affinity, but * there's no easy reverse mapping. For simplicity, * we assume that if this node is a procdir, its * parent isn't (which is correct as long as * descendents of procdir nodes are never procdir * nodes themselves) */ if (pd->pn_type == pfstype_procdir) pid = NO_PID; pfs_lock(pd); pn = pd->pn_parent; pfs_unlock(pd); goto got_pnode; } pfs_lock(pd); /* named node */ for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next) if (pn->pn_type == pfstype_procdir) pdn = pn; else if (strncmp(pname, pn->pn_name, namelen) == 0 && pn->pn_name[namelen] == '\0') { pfs_unlock(pd); goto got_pnode; } /* process dependent node */ if ((pn = pdn) != NULL) { pid = 0; for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i) if ((pid = pid * 10 + pname[i] - '0') > PID_MAX) break; if (i == cnp->cn_namelen) { pfs_unlock(pd); goto got_pnode; } } pfs_unlock(pd); PFS_RETURN (ENOENT); got_pnode: pfs_assert_not_owned(pd); pfs_assert_not_owned(pn); visible = pfs_visible(curthread, pn, pid, NULL); if (!visible) { error = ENOENT; goto failed; } error = pfs_vncache_alloc(mp, vpp, pn, pid); if (error) goto failed; if (cnp->cn_flags & ISDOTDOT) { vfs_unbusy(mp); vn_lock(vn, LK_EXCLUSIVE | LK_RETRY); if (VN_IS_DOOMED(vn)) { vput(*vpp); *vpp = NULL; PFS_RETURN(ENOENT); } } if (cnp->cn_flags & MAKEENTRY && !VN_IS_DOOMED(vn)) cache_enter(vn, *vpp, cnp); PFS_RETURN (0); failed: if (cnp->cn_flags & ISDOTDOT) { vfs_unbusy(mp); vn_lock(vn, LK_EXCLUSIVE | LK_RETRY); *vpp = NULL; } PFS_RETURN(error); } /* * Open a file or directory. */ static int pfs_open(struct vop_open_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; int mode = va->a_mode; PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode)); pfs_assert_not_owned(pn); /* check if the requested mode is permitted */ if (((mode & FREAD) && !(mode & PFS_RD)) || ((mode & FWRITE) && !(mode & PFS_WR))) PFS_RETURN (EPERM); /* we don't support locking */ if ((mode & O_SHLOCK) || (mode & O_EXLOCK)) PFS_RETURN (EOPNOTSUPP); PFS_RETURN (0); } struct sbuf_seek_helper { off_t skip_bytes; struct uio *uio; }; static int pfs_sbuf_uio_drain(void *arg, const char *data, int len) { struct sbuf_seek_helper *ssh; struct uio *uio; int error, skipped; ssh = arg; uio = ssh->uio; skipped = 0; /* Need to discard first uio_offset bytes. */ if (ssh->skip_bytes > 0) { if (ssh->skip_bytes >= len) { ssh->skip_bytes -= len; return (len); } data += ssh->skip_bytes; len -= ssh->skip_bytes; skipped = ssh->skip_bytes; ssh->skip_bytes = 0; } error = uiomove(__DECONST(void *, data), len, uio); if (error != 0) return (-error); /* * The fill function has more to emit, but the reader is finished. * This is similar to the truncated read case for non-draining PFS * sbufs, and should be handled appropriately in fill-routines. */ if (uio->uio_resid == 0) return (-ENOBUFS); return (skipped + len); } /* * Read from a file */ static int pfs_read(struct vop_read_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; struct uio *uio = va->a_uio; struct proc *proc; struct sbuf *sb = NULL; int error, locked; off_t buflen, buflim; struct sbuf_seek_helper ssh; PFS_TRACE(("%s", pn->pn_name)); pfs_assert_not_owned(pn); if (vn->v_type != VREG) PFS_RETURN (EINVAL); KASSERT_PN_IS_FILE(pn); if (!(pn->pn_flags & PFS_RD)) PFS_RETURN (EBADF); if (pn->pn_fill == NULL) PFS_RETURN (EIO); /* * This is necessary because either process' privileges may * have changed since the open() call. */ if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) PFS_RETURN (EIO); if (proc != NULL) { _PHOLD(proc); PROC_UNLOCK(proc); } vhold(vn); locked = VOP_ISLOCKED(vn); VOP_UNLOCK(vn); if (pn->pn_flags & PFS_RAWRD) { PFS_TRACE(("%zd resid", uio->uio_resid)); error = pn_fill(curthread, proc, pn, NULL, uio); PFS_TRACE(("%zd resid", uio->uio_resid)); goto ret; } if (uio->uio_resid < 0 || uio->uio_offset < 0 || uio->uio_resid > OFF_MAX - uio->uio_offset) { error = EINVAL; goto ret; } buflen = uio->uio_offset + uio->uio_resid + 1; if (pn->pn_flags & PFS_AUTODRAIN) /* * We can use a smaller buffer if we can stream output to the * consumer. */ buflim = PAGE_SIZE; else buflim = PFS_MAXBUFSIZ; if (buflen > buflim) buflen = buflim; sb = sbuf_new(sb, NULL, buflen, 0); if (sb == NULL) { error = EIO; goto ret; } if (pn->pn_flags & PFS_AUTODRAIN) { ssh.skip_bytes = uio->uio_offset; ssh.uio = uio; sbuf_set_drain(sb, pfs_sbuf_uio_drain, &ssh); } error = pn_fill(curthread, proc, pn, sb, uio); if (error) { sbuf_delete(sb); goto ret; } /* * XXX: If the buffer overflowed, sbuf_len() will not return * the data length. Then just use the full length because an * overflowed sbuf must be full. */ error = sbuf_finish(sb); if ((pn->pn_flags & PFS_AUTODRAIN)) { /* * ENOBUFS just indicates early termination of the fill * function as the caller's buffer was already filled. Squash * to zero. */ if (uio->uio_resid == 0 && error == ENOBUFS) error = 0; } else { if (error == 0) buflen = sbuf_len(sb); else /* The trailing byte is not valid. */ buflen--; error = uiomove_frombuf(sbuf_data(sb), buflen, uio); } sbuf_delete(sb); ret: vn_lock(vn, locked | LK_RETRY); vdrop(vn); if (proc != NULL) PRELE(proc); PFS_RETURN (error); } /* * Iterate through directory entries */ static int pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd, struct pfs_node **pn, struct proc **p) { int visible; sx_assert(&allproc_lock, SX_SLOCKED); pfs_assert_owned(pd); again: if (*pn == NULL) { /* first node */ *pn = pd->pn_nodes; } else if ((*pn)->pn_type != pfstype_procdir) { /* next node */ *pn = (*pn)->pn_next; } if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) { /* next process */ if (*p == NULL) *p = LIST_FIRST(&allproc); else *p = LIST_NEXT(*p, p_list); /* out of processes: next node */ if (*p == NULL) *pn = (*pn)->pn_next; else PROC_LOCK(*p); } if ((*pn) == NULL) return (-1); if (*p != NULL) { visible = pfs_visible_proc(td, *pn, *p); PROC_UNLOCK(*p); } else if (proc != NULL) { visible = pfs_visible_proc(td, *pn, proc); } else { visible = pn_vis(td, NULL, *pn); } if (!visible) goto again; return (0); } /* Directory entry list */ struct pfsentry { STAILQ_ENTRY(pfsentry) link; struct dirent entry; }; STAILQ_HEAD(pfsdirentlist, pfsentry); /* * Return directory entries. */ static int pfs_readdir(struct vop_readdir_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pd = pvd->pvd_pn; pid_t pid = pvd->pvd_pid; struct proc *p, *proc; struct pfs_node *pn; struct uio *uio; struct pfsentry *pfsent, *pfsent2; struct pfsdirentlist lst; off_t coffset, offset; int error, i, resid; STAILQ_INIT(&lst); error = 0; KASSERT(pd->pn_info == vn->v_mount->mnt_data, ("%s(): pn_info does not match mountpoint", __func__)); PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid)); pfs_assert_not_owned(pd); if (va->a_eofflag != NULL) *va->a_eofflag = 0; if (vn->v_type != VDIR) PFS_RETURN (ENOTDIR); KASSERT_PN_IS_DIR(pd); uio = va->a_uio; /* only allow reading entire entries */ offset = uio->uio_offset; resid = uio->uio_resid; if (offset < 0 || offset % PFS_DELEN != 0 || (resid && resid < PFS_DELEN)) PFS_RETURN (EINVAL); if (resid == 0) PFS_RETURN (0); proc = NULL; if (pid != NO_PID && !pfs_lookup_proc(pid, &proc)) PFS_RETURN (ENOENT); /* * The allproc lock is required in pfs_iterate() for procdir * directories. */ sx_slock(&allproc_lock); pfs_lock(pd); KASSERT(pid == NO_PID || proc != NULL, ("%s(): no process for pid %lu", __func__, (unsigned long)pid)); if (pid != NO_PID) { PROC_LOCK(proc); /* check if the directory is visible to the caller */ if (!pfs_visible_proc(curthread, pd, proc)) { _PRELE(proc); PROC_UNLOCK(proc); pfs_unlock(pd); sx_sunlock(&allproc_lock); PFS_RETURN (ENOENT); } } for (pn = NULL, p = NULL, coffset = 0; resid >= PFS_DELEN; coffset += PFS_DELEN) { if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) { if (va->a_eofflag != NULL) *va->a_eofflag = 1; break; } if (coffset < offset) continue; if ((pfsent = malloc(sizeof(struct pfsentry), M_IOV, M_NOWAIT | M_ZERO)) == NULL) { error = ENOMEM; break; } pfsent->entry.d_reclen = PFS_DELEN; pfsent->entry.d_fileno = pn_fileno(pn, pid); /* PFS_DELEN was picked to fit PFS_NAMLEN */ for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i) pfsent->entry.d_name[i] = pn->pn_name[i]; pfsent->entry.d_namlen = i; /* NOTE: d_off is the offset of the *next* entry. */ pfsent->entry.d_off = offset + PFS_DELEN; switch (pn->pn_type) { case pfstype_procdir: KASSERT(p != NULL, ("reached procdir node with p == NULL")); pfsent->entry.d_namlen = snprintf(pfsent->entry.d_name, PFS_NAMELEN, "%d", p->p_pid); /* fall through */ case pfstype_root: case pfstype_dir: case pfstype_this: case pfstype_parent: pfsent->entry.d_type = DT_DIR; break; case pfstype_file: pfsent->entry.d_type = DT_REG; break; case pfstype_symlink: pfsent->entry.d_type = DT_LNK; break; default: panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type); } PFS_TRACE(("%s", pfsent->entry.d_name)); dirent_terminate(&pfsent->entry); STAILQ_INSERT_TAIL(&lst, pfsent, link); offset += PFS_DELEN; resid -= PFS_DELEN; } if (proc != NULL) { _PRELE(proc); PROC_UNLOCK(proc); } pfs_unlock(pd); sx_sunlock(&allproc_lock); i = 0; STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) { if (error == 0) error = uiomove(&pfsent->entry, PFS_DELEN, uio); free(pfsent, M_IOV); i++; } PFS_TRACE(("%ju bytes", (uintmax_t)(i * PFS_DELEN))); PFS_RETURN (error); } /* * Read a symbolic link */ static int pfs_readlink(struct vop_readlink_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; struct uio *uio = va->a_uio; struct proc *proc = NULL; char buf[PATH_MAX]; struct sbuf sb; int error, locked; PFS_TRACE(("%s", pn->pn_name)); pfs_assert_not_owned(pn); if (vn->v_type != VLNK) PFS_RETURN (EINVAL); KASSERT_PN_IS_LINK(pn); if (pn->pn_fill == NULL) PFS_RETURN (EIO); if (pvd->pvd_pid != NO_PID) { if ((proc = pfind(pvd->pvd_pid)) == NULL) PFS_RETURN (EIO); if (proc->p_flag & P_WEXIT) { PROC_UNLOCK(proc); PFS_RETURN (EIO); } _PHOLD(proc); PROC_UNLOCK(proc); } vhold(vn); locked = VOP_ISLOCKED(vn); VOP_UNLOCK(vn); /* sbuf_new() can't fail with a static buffer */ sbuf_new(&sb, buf, sizeof buf, 0); error = pn_fill(curthread, proc, pn, &sb, NULL); if (proc != NULL) PRELE(proc); vn_lock(vn, locked | LK_RETRY); vdrop(vn); if (error) { sbuf_delete(&sb); PFS_RETURN (error); } if (sbuf_finish(&sb) != 0) { sbuf_delete(&sb); PFS_RETURN (ENAMETOOLONG); } error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio); sbuf_delete(&sb); PFS_RETURN (error); } /* * Reclaim a vnode */ static int pfs_reclaim(struct vop_reclaim_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; PFS_TRACE(("%s", pn->pn_name)); pfs_assert_not_owned(pn); return (pfs_vncache_free(va->a_vp)); } /* * Set attributes */ static int pfs_setattr(struct vop_setattr_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; PFS_TRACE(("%s", pn->pn_name)); pfs_assert_not_owned(pn); /* Silently ignore unchangeable attributes. */ PFS_RETURN (0); } /* * Write to a file */ static int pfs_write(struct vop_write_args *va) { struct vnode *vn = va->a_vp; struct pfs_vdata *pvd = vn->v_data; struct pfs_node *pn = pvd->pvd_pn; struct uio *uio = va->a_uio; struct proc *proc; struct sbuf sb; int error; PFS_TRACE(("%s", pn->pn_name)); pfs_assert_not_owned(pn); if (vn->v_type != VREG) PFS_RETURN (EINVAL); KASSERT_PN_IS_FILE(pn); if (!(pn->pn_flags & PFS_WR)) PFS_RETURN (EBADF); if (pn->pn_fill == NULL) PFS_RETURN (EIO); if (uio->uio_resid > PFS_MAXBUFSIZ) PFS_RETURN (EIO); /* * This is necessary because either process' privileges may * have changed since the open() call. */ if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) PFS_RETURN (EIO); if (proc != NULL) { _PHOLD(proc); PROC_UNLOCK(proc); } if (pn->pn_flags & PFS_RAWWR) { error = pn_fill(curthread, proc, pn, NULL, uio); if (proc != NULL) PRELE(proc); PFS_RETURN (error); } sbuf_uionew(&sb, uio, &error); if (error) { if (proc != NULL) PRELE(proc); PFS_RETURN (error); } error = pn_fill(curthread, proc, pn, &sb, uio); sbuf_delete(&sb); if (proc != NULL) PRELE(proc); PFS_RETURN (error); } /* * Vnode operations */ struct vop_vector pfs_vnodeops = { .vop_default = &default_vnodeops, .vop_access = pfs_access, .vop_cachedlookup = pfs_lookup, .vop_close = pfs_close, .vop_create = VOP_EOPNOTSUPP, .vop_getattr = pfs_getattr, .vop_getextattr = pfs_getextattr, .vop_ioctl = pfs_ioctl, .vop_link = VOP_EOPNOTSUPP, .vop_lookup = vfs_cache_lookup, .vop_mkdir = VOP_EOPNOTSUPP, .vop_mknod = VOP_EOPNOTSUPP, .vop_open = pfs_open, .vop_read = pfs_read, .vop_readdir = pfs_readdir, .vop_readlink = pfs_readlink, .vop_reclaim = pfs_reclaim, .vop_remove = VOP_EOPNOTSUPP, .vop_rename = VOP_EOPNOTSUPP, .vop_rmdir = VOP_EOPNOTSUPP, .vop_setattr = pfs_setattr, .vop_symlink = VOP_EOPNOTSUPP, .vop_vptocnp = pfs_vptocnp, .vop_write = pfs_write, .vop_add_writecount = vop_stdadd_writecount_nomsync, /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */ }; VFS_VOP_VECTOR_REGISTER(pfs_vnodeops); diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c index a97bc22b3aca..e960d8d78b66 100644 --- a/sys/fs/smbfs/smbfs_vnops.c +++ b/sys/fs/smbfs/smbfs_vnops.c @@ -1,1249 +1,1249 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2000-2001 Boris Popov * All rights reserved. * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Prototypes for SMBFS vnode operations */ static vop_create_t smbfs_create; static vop_mknod_t smbfs_mknod; static vop_open_t smbfs_open; static vop_close_t smbfs_close; static vop_access_t smbfs_access; static vop_getattr_t smbfs_getattr; static vop_setattr_t smbfs_setattr; static vop_read_t smbfs_read; static vop_write_t smbfs_write; static vop_fsync_t smbfs_fsync; static vop_remove_t smbfs_remove; static vop_link_t smbfs_link; static vop_lookup_t smbfs_lookup; static vop_rename_t smbfs_rename; static vop_mkdir_t smbfs_mkdir; static vop_rmdir_t smbfs_rmdir; static vop_symlink_t smbfs_symlink; static vop_readdir_t smbfs_readdir; static vop_strategy_t smbfs_strategy; static vop_print_t smbfs_print; static vop_pathconf_t smbfs_pathconf; static vop_advlock_t smbfs_advlock; static vop_getextattr_t smbfs_getextattr; struct vop_vector smbfs_vnodeops = { .vop_default = &default_vnodeops, .vop_access = smbfs_access, .vop_advlock = smbfs_advlock, .vop_close = smbfs_close, .vop_create = smbfs_create, .vop_fsync = smbfs_fsync, .vop_getattr = smbfs_getattr, .vop_getextattr = smbfs_getextattr, .vop_getpages = smbfs_getpages, .vop_inactive = smbfs_inactive, .vop_ioctl = smbfs_ioctl, .vop_link = smbfs_link, .vop_lookup = smbfs_lookup, .vop_mkdir = smbfs_mkdir, .vop_mknod = smbfs_mknod, .vop_open = smbfs_open, .vop_pathconf = smbfs_pathconf, .vop_print = smbfs_print, .vop_putpages = smbfs_putpages, .vop_read = smbfs_read, .vop_readdir = smbfs_readdir, .vop_reclaim = smbfs_reclaim, .vop_remove = smbfs_remove, .vop_rename = smbfs_rename, .vop_rmdir = smbfs_rmdir, .vop_setattr = smbfs_setattr, /* .vop_setextattr = smbfs_setextattr,*/ .vop_strategy = smbfs_strategy, .vop_symlink = smbfs_symlink, .vop_write = smbfs_write, }; VFS_VOP_VECTOR_REGISTER(smbfs_vnodeops); static int smbfs_access(struct vop_access_args *ap) { struct vnode *vp = ap->a_vp; accmode_t accmode = ap->a_accmode; mode_t mpmode; struct smbmount *smp = VTOSMBFS(vp); SMBVDEBUG("\n"); if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { switch (vp->v_type) { case VREG: case VDIR: case VLNK: return EROFS; default: break; } } mpmode = vp->v_type == VREG ? smp->sm_file_mode : smp->sm_dir_mode; return (vaccess(vp->v_type, mpmode, smp->sm_uid, smp->sm_gid, ap->a_accmode, ap->a_cred)); } /* ARGSUSED */ static int smbfs_open(struct vop_open_args *ap) { struct vnode *vp = ap->a_vp; struct smbnode *np = VTOSMB(vp); struct smb_cred *scred; struct vattr vattr; int mode = ap->a_mode; int error, accmode; SMBVDEBUG("%s,%d\n", np->n_name, (np->n_flag & NOPEN) != 0); if (vp->v_type != VREG && vp->v_type != VDIR) { SMBFSERR("open eacces vtype=%d\n", vp->v_type); return EACCES; } if (vp->v_type == VDIR) { np->n_flag |= NOPEN; return 0; } if (np->n_flag & NMODIFIED) { if ((error = smbfs_vinvalbuf(vp, ap->a_td)) == EINTR) return error; smbfs_attr_cacheremove(vp); error = VOP_GETATTR(vp, &vattr, ap->a_cred); if (error) return error; np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; } else { error = VOP_GETATTR(vp, &vattr, ap->a_cred); if (error) return error; if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { error = smbfs_vinvalbuf(vp, ap->a_td); if (error == EINTR) return error; np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; } } if ((np->n_flag & NOPEN) != 0) return 0; /* * Use DENYNONE to give unixy semantics of permitting * everything not forbidden by permissions. Ie denial * is up to server with clients/openers needing to use * advisory locks for further control. */ accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW; scred = smbfs_malloc_scred(); smb_makescred(scred, ap->a_td, ap->a_cred); error = smbfs_smb_open(np, accmode, scred); if (error) { if (mode & FWRITE) return EACCES; else if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; error = smbfs_smb_open(np, accmode, scred); } } if (error == 0) { np->n_flag |= NOPEN; vnode_create_vobject(ap->a_vp, vattr.va_size, ap->a_td); } smbfs_attr_cacheremove(vp); smbfs_free_scred(scred); return error; } static int smbfs_close(struct vop_close_args *ap) { struct vnode *vp = ap->a_vp; struct thread *td = ap->a_td; struct smbnode *np = VTOSMB(vp); struct smb_cred *scred; if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0 && np->n_dirseq != NULL) { scred = smbfs_malloc_scred(); smb_makescred(scred, td, ap->a_cred); smbfs_findclose(np->n_dirseq, scred); smbfs_free_scred(scred); np->n_dirseq = NULL; } return 0; } /* * smbfs_getattr call from vfs. */ static int smbfs_getattr(struct vop_getattr_args *ap) { struct vnode *vp = ap->a_vp; struct smbnode *np = VTOSMB(vp); struct vattr *va=ap->a_vap; struct smbfattr fattr; struct smb_cred *scred; u_quad_t oldsize; int error; SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_vflag & VV_ROOT) != 0); error = smbfs_attr_cachelookup(vp, va); if (!error) return 0; SMBVDEBUG("not in the cache\n"); scred = smbfs_malloc_scred(); smb_makescred(scred, curthread, ap->a_cred); oldsize = np->n_size; error = smbfs_smb_lookup(np, NULL, 0, &fattr, scred); if (error) { SMBVDEBUG("error %d\n", error); smbfs_free_scred(scred); return error; } smbfs_attr_cacheenter(vp, &fattr); smbfs_attr_cachelookup(vp, va); if (np->n_flag & NOPEN) np->n_size = oldsize; smbfs_free_scred(scred); return 0; } static int smbfs_setattr(struct vop_setattr_args *ap) { struct vnode *vp = ap->a_vp; struct smbnode *np = VTOSMB(vp); struct vattr *vap = ap->a_vap; struct timespec *mtime, *atime; struct smb_cred *scred; struct smb_share *ssp = np->n_mount->sm_share; struct smb_vc *vcp = SSTOVC(ssp); struct thread *td = curthread; u_quad_t tsize = 0; int isreadonly, doclose, error = 0; int old_n_dosattr; SMBVDEBUG("\n"); isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); /* * Disallow write attempts if the filesystem is mounted read-only. */ if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL || vap->va_flags != VNOVAL) && isreadonly) return EROFS; /* * We only support setting four flags. Don't allow setting others. * * We map UF_READONLY to SMB_FA_RDONLY, unlike the MacOS X version * of this code, which maps both UF_IMMUTABLE AND SF_IMMUTABLE to * SMB_FA_RDONLY. The immutable flags have different semantics * than readonly, which is the reason for the difference. */ if (vap->va_flags != VNOVAL) { if (vap->va_flags & ~(UF_HIDDEN|UF_SYSTEM|UF_ARCHIVE| UF_READONLY)) return EINVAL; } scred = smbfs_malloc_scred(); smb_makescred(scred, td, ap->a_cred); if (vap->va_size != VNOVAL) { switch (vp->v_type) { case VDIR: error = EISDIR; goto out; case VREG: break; default: error = EINVAL; goto out; } if (isreadonly) { error = EROFS; goto out; } doclose = 0; vnode_pager_setsize(vp, (u_long)vap->va_size); tsize = np->n_size; np->n_size = vap->va_size; if ((np->n_flag & NOPEN) == 0) { error = smbfs_smb_open(np, SMB_SM_DENYNONE|SMB_AM_OPENRW, scred); if (error == 0) doclose = 1; } if (error == 0) error = smbfs_smb_setfsize(np, (int64_t)vap->va_size, scred); if (doclose) smbfs_smb_close(ssp, np->n_fid, NULL, scred); if (error) { np->n_size = tsize; vnode_pager_setsize(vp, (u_long)tsize); goto out; } } if ((vap->va_flags != VNOVAL) || (vap->va_mode != (mode_t)VNOVAL)) { old_n_dosattr = np->n_dosattr; if (vap->va_mode != (mode_t)VNOVAL) { if (vap->va_mode & S_IWUSR) np->n_dosattr &= ~SMB_FA_RDONLY; else np->n_dosattr |= SMB_FA_RDONLY; } if (vap->va_flags != VNOVAL) { if (vap->va_flags & UF_HIDDEN) np->n_dosattr |= SMB_FA_HIDDEN; else np->n_dosattr &= ~SMB_FA_HIDDEN; if (vap->va_flags & UF_SYSTEM) np->n_dosattr |= SMB_FA_SYSTEM; else np->n_dosattr &= ~SMB_FA_SYSTEM; if (vap->va_flags & UF_ARCHIVE) np->n_dosattr |= SMB_FA_ARCHIVE; else np->n_dosattr &= ~SMB_FA_ARCHIVE; /* * We only support setting the immutable / readonly * bit for regular files. According to comments in * the MacOS X version of this code, supporting the * readonly bit on directories doesn't do the same * thing in Windows as in Unix. */ if (vp->v_type == VREG) { if (vap->va_flags & UF_READONLY) np->n_dosattr |= SMB_FA_RDONLY; else np->n_dosattr &= ~SMB_FA_RDONLY; } } if (np->n_dosattr != old_n_dosattr) { error = smbfs_smb_setpattr(np, np->n_dosattr, NULL, scred); if (error) goto out; } } mtime = atime = NULL; if (vap->va_mtime.tv_sec != VNOVAL) mtime = &vap->va_mtime; if (vap->va_atime.tv_sec != VNOVAL) atime = &vap->va_atime; if (mtime != atime) { if (vap->va_vaflags & VA_UTIMES_NULL) { error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); if (error) error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td); } else error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); #if 0 if (mtime == NULL) mtime = &np->n_mtime; if (atime == NULL) atime = &np->n_atime; #endif /* * If file is opened, then we can use handle based calls. * If not, use path based ones. */ if ((np->n_flag & NOPEN) == 0) { if (vcp->vc_flags & SMBV_WIN95) { error = VOP_OPEN(vp, FWRITE, ap->a_cred, td, NULL); if (!error) { /* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, scred); VOP_GETATTR(vp, &vattr, ap->a_cred); */ if (mtime) np->n_mtime = *mtime; VOP_CLOSE(vp, FWRITE, ap->a_cred, td); } } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, scred);*/ } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); } else { error = smbfs_smb_setpattr(np, 0, mtime, scred); } } else { if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { error = smbfs_smb_setfattrNT(np, 0, mtime, atime, scred); } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { error = smbfs_smb_setftime(np, mtime, atime, scred); } else { /* * I have no idea how to handle this for core * level servers. The possible solution is to * update mtime after file is closed. */ SMBERROR("can't update times on an opened file\n"); } } } /* * Invalidate attribute cache in case if server doesn't set * required attributes. */ smbfs_attr_cacheremove(vp); /* invalidate cache */ VOP_GETATTR(vp, vap, ap->a_cred); np->n_mtime.tv_sec = vap->va_mtime.tv_sec; out: smbfs_free_scred(scred); return error; } /* * smbfs_read call. */ static int smbfs_read(struct vop_read_args *ap) { struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; SMBVDEBUG("\n"); if (vp->v_type != VREG && vp->v_type != VDIR) return EPERM; return smbfs_readvnode(vp, uio, ap->a_cred, NULL); } static int smbfs_write(struct vop_write_args *ap) { struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; SMBVDEBUG("%d,ofs=%jd,sz=%zd\n",vp->v_type, (intmax_t)uio->uio_offset, uio->uio_resid); if (vp->v_type != VREG) return (EPERM); return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); } /* * smbfs_create call * Create a regular file. On entry the directory to contain the file being * created is locked. We must release before we return. We must also free * the pathname buffer pointed at by cnp->cn_pnbuf, always on error. */ static int smbfs_create(struct vop_create_args *ap) { struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct vnode **vpp=ap->a_vpp; struct componentname *cnp = ap->a_cnp; struct smbnode *dnp = VTOSMB(dvp); struct vnode *vp; struct vattr vattr; struct smbfattr fattr; struct smb_cred *scred; char *name = cnp->cn_nameptr; int nmlen = cnp->cn_namelen; int error; SMBVDEBUG("\n"); *vpp = NULL; if (vap->va_type != VREG) return EOPNOTSUPP; if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) return error; scred = smbfs_malloc_scred(); smb_makescred(scred, curthread, cnp->cn_cred); error = smbfs_smb_create(dnp, name, nmlen, scred); if (error) goto out; error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, scred); if (error) goto out; error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); if (error) goto out; *vpp = vp; if (cnp->cn_flags & MAKEENTRY) cache_enter(dvp, vp, cnp); out: smbfs_free_scred(scred); return error; } static int smbfs_remove(struct vop_remove_args *ap) { struct vnode *vp = ap->a_vp; /* struct vnode *dvp = ap->a_dvp;*/ struct componentname *cnp = ap->a_cnp; struct smbnode *np = VTOSMB(vp); struct smb_cred *scred; int error; if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0 || vrefcnt(vp) != 1) return EPERM; scred = smbfs_malloc_scred(); smb_makescred(scred, curthread, cnp->cn_cred); error = smbfs_smb_delete(np, scred); if (error == 0) np->n_flag |= NGONE; cache_purge(vp); smbfs_free_scred(scred); return error; } /* * smbfs_file rename call */ static int smbfs_rename(struct vop_rename_args *ap) { struct vnode *fvp = ap->a_fvp; struct vnode *tvp = ap->a_tvp; struct vnode *fdvp = ap->a_fdvp; struct vnode *tdvp = ap->a_tdvp; struct componentname *tcnp = ap->a_tcnp; /* struct componentname *fcnp = ap->a_fcnp;*/ struct smb_cred *scred; #ifdef notnow u_int16_t flags = 6; #endif int error=0; scred = NULL; /* Check for cross-device rename */ if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { error = EXDEV; goto out; } if (tvp && vrefcnt(tvp) > 1) { error = EBUSY; goto out; } #ifdef notnow flags = 0x10; /* verify all writes */ #endif if (fvp->v_type == VDIR) { #ifdef notnow flags |= 2; #endif } else if (fvp->v_type == VREG) { #ifdef notnow flags |= 1; #endif } else { return EINVAL; } scred = smbfs_malloc_scred(); smb_makescred(scred, curthread, tcnp->cn_cred); /* * It seems that Samba doesn't implement SMB_COM_MOVE call... */ #ifdef notnow if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), tcnp->cn_nameptr, tcnp->cn_namelen, flags, scred); } else #endif { /* * We have to do the work atomicaly */ if (tvp && tvp != fvp) { error = smbfs_smb_delete(VTOSMB(tvp), scred); if (error) goto out_cacherem; VTOSMB(fvp)->n_flag |= NGONE; } error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), tcnp->cn_nameptr, tcnp->cn_namelen, scred); } if (fvp->v_type == VDIR) { if (tvp != NULL && tvp->v_type == VDIR) cache_purge(tdvp); cache_purge(fdvp); } out_cacherem: smbfs_attr_cacheremove(fdvp); smbfs_attr_cacheremove(tdvp); out: smbfs_free_scred(scred); if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp) vput(tvp); vrele(fdvp); vrele(fvp); #ifdef possible_mistake vgone(fvp); if (tvp) vgone(tvp); #endif return error; } /* * somtime it will come true... */ static int smbfs_link(struct vop_link_args *ap) { return EOPNOTSUPP; } /* * smbfs_symlink link create call. * Sometime it will be functional... */ static int smbfs_symlink(struct vop_symlink_args *ap) { return EOPNOTSUPP; } static int smbfs_mknod(struct vop_mknod_args *ap) { return EOPNOTSUPP; } static int smbfs_mkdir(struct vop_mkdir_args *ap) { struct vnode *dvp = ap->a_dvp; /* struct vattr *vap = ap->a_vap;*/ struct vnode *vp; struct componentname *cnp = ap->a_cnp; struct smbnode *dnp = VTOSMB(dvp); struct vattr vattr; struct smb_cred *scred; struct smbfattr fattr; char *name = cnp->cn_nameptr; int len = cnp->cn_namelen; int error; if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) { return error; } if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) return EEXIST; scred = smbfs_malloc_scred(); smb_makescred(scred, curthread, cnp->cn_cred); error = smbfs_smb_mkdir(dnp, name, len, scred); if (error) goto out; error = smbfs_smb_lookup(dnp, name, len, &fattr, scred); if (error) goto out; error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); if (error) goto out; *ap->a_vpp = vp; out: smbfs_free_scred(scred); return error; } /* * smbfs_remove directory call */ static int smbfs_rmdir(struct vop_rmdir_args *ap) { struct vnode *vp = ap->a_vp; struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; /* struct smbmount *smp = VTOSMBFS(vp);*/ struct smbnode *dnp = VTOSMB(dvp); struct smbnode *np = VTOSMB(vp); struct smb_cred *scred; int error; if (dvp == vp) return EINVAL; scred = smbfs_malloc_scred(); smb_makescred(scred, curthread, cnp->cn_cred); error = smbfs_smb_rmdir(np, scred); if (error == 0) np->n_flag |= NGONE; dnp->n_flag |= NMODIFIED; smbfs_attr_cacheremove(dvp); /* cache_purge(dvp);*/ cache_purge(vp); smbfs_free_scred(scred); return error; } /* * smbfs_readdir call */ static int smbfs_readdir(struct vop_readdir_args *ap) { struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; if (vp->v_type != VDIR) return (EPERM); #ifdef notnow if (ap->a_ncookies) { printf("smbfs_readdir: no support for cookies now..."); return (EOPNOTSUPP); } #endif return (smbfs_readvnode(vp, uio, ap->a_cred, ap->a_eofflag)); } /* ARGSUSED */ static int smbfs_fsync(struct vop_fsync_args *ap) { /* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ return (0); } static int smbfs_print(struct vop_print_args *ap) { struct vnode *vp = ap->a_vp; struct smbnode *np = VTOSMB(vp); if (np == NULL) { printf("no smbnode data\n"); return (0); } printf("\tname = %s, parent = %p, open = %d\n", np->n_name, np->n_parent ? np->n_parent : NULL, (np->n_flag & NOPEN) != 0); return (0); } static int smbfs_pathconf(struct vop_pathconf_args *ap) { struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); struct smb_vc *vcp = SSTOVC(smp->sm_share); long *retval = ap->a_retval; int error = 0; switch (ap->a_name) { case _PC_FILESIZEBITS: if (vcp->vc_sopt.sv_caps & (SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX)) *retval = 64; else *retval = 32; break; case _PC_NAME_MAX: *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; break; case _PC_PATH_MAX: *retval = 800; /* XXX: a correct one ? */ break; case _PC_NO_TRUNC: *retval = 1; break; case _PC_HAS_HIDDENSYSTEM: *retval = 1; break; default: error = vop_stdpathconf(ap); } return error; } static int smbfs_strategy(struct vop_strategy_args *ap) { struct buf *bp=ap->a_bp; struct ucred *cr; struct thread *td; SMBVDEBUG("\n"); if (bp->b_flags & B_ASYNC) td = (struct thread *)0; else td = curthread; /* XXX */ if (bp->b_iocmd == BIO_READ) cr = bp->b_rcred; else cr = bp->b_wcred; if ((bp->b_flags & B_ASYNC) == 0 ) (void)smbfs_doio(ap->a_vp, bp, cr, td); return (0); } int smbfs_ioctl(struct vop_ioctl_args *ap) { return ENOTTY; } static char smbfs_atl[] = "rhsvda"; static int smbfs_getextattr(struct vop_getextattr_args *ap) /* { IN struct vnode *a_vp; IN char *a_name; INOUT struct uio *a_uio; IN struct ucred *a_cred; IN struct thread *a_td; }; */ { struct vnode *vp = ap->a_vp; struct thread *td = ap->a_td; struct ucred *cred = ap->a_cred; struct uio *uio = ap->a_uio; const char *name = ap->a_name; struct smbnode *np = VTOSMB(vp); struct vattr vattr; char buf[10]; int i, attr, error; error = VOP_ACCESS(vp, VREAD, cred, td); if (error) return error; error = VOP_GETATTR(vp, &vattr, cred); if (error) return error; if (strcmp(name, "dosattr") == 0) { attr = np->n_dosattr; for (i = 0; i < 6; i++, attr >>= 1) buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; buf[i] = 0; error = uiomove(buf, i, uio); } else error = EINVAL; return error; } /* * Since we expected to support F_GETLK (and SMB protocol has no such function), * it is necessary to use lf_advlock(). It would be nice if this function had * a callback mechanism because it will help to improve a level of consistency. */ int smbfs_advlock(struct vop_advlock_args *ap) { struct vnode *vp = ap->a_vp; struct smbnode *np = VTOSMB(vp); struct flock *fl = ap->a_fl; caddr_t id = (caddr_t)1 /* ap->a_id */; /* int flags = ap->a_flags;*/ struct thread *td = curthread; struct smb_cred *scred; u_quad_t size; off_t start, end, oadd; int error, lkop; if (vp->v_type == VDIR) { /* * SMB protocol have no support for directory locking. * Although locks can be processed on local machine, I don't * think that this is a good idea, because some programs * can work wrong assuming directory is locked. So, we just * return 'operation not supported */ return EOPNOTSUPP; } size = np->n_size; switch (fl->l_whence) { case SEEK_SET: case SEEK_CUR: start = fl->l_start; break; case SEEK_END: if (size > OFF_MAX || (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) return EOVERFLOW; start = size + fl->l_start; break; default: return EINVAL; } if (start < 0) return EINVAL; if (fl->l_len < 0) { if (start == 0) return EINVAL; end = start - 1; start += fl->l_len; if (start < 0) return EINVAL; } else if (fl->l_len == 0) end = -1; else { oadd = fl->l_len - 1; if (oadd > OFF_MAX - start) return EOVERFLOW; end = start + oadd; } scred = smbfs_malloc_scred(); smb_makescred(scred, td, td->td_ucred); switch (ap->a_op) { case F_SETLK: switch (fl->l_type) { case F_WRLCK: lkop = SMB_LOCK_EXCL; break; case F_RDLCK: lkop = SMB_LOCK_SHARED; break; case F_UNLCK: lkop = SMB_LOCK_RELEASE; break; default: smbfs_free_scred(scred); return EINVAL; } error = lf_advlock(ap, &vp->v_lockf, size); if (error) break; lkop = SMB_LOCK_EXCL; error = smbfs_smb_lock(np, lkop, id, start, end, scred); if (error) { int oldtype = fl->l_type; fl->l_type = F_UNLCK; ap->a_op = F_UNLCK; lf_advlock(ap, &vp->v_lockf, size); fl->l_type = oldtype; } break; case F_UNLCK: lf_advlock(ap, &vp->v_lockf, size); error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, scred); break; case F_GETLK: error = lf_advlock(ap, &vp->v_lockf, size); break; default: smbfs_free_scred(scred); return EINVAL; } smbfs_free_scred(scred); return error; } static int smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) { static const char *badchars = "*/:<>?"; static const char *badchars83 = " +|,[]=;"; const char *cp; int i, error; /* * Backslash characters, being a path delimiter, are prohibited * within a path component even for LOOKUP operations. */ if (strchr(name, '\\') != NULL) return ENOENT; if (nameiop == LOOKUP) return 0; error = ENOENT; if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { /* * Name should conform 8.3 format */ if (nmlen > 12) return ENAMETOOLONG; cp = strchr(name, '.'); if (cp == NULL) return error; if (cp == name || (cp - name) > 8) return error; cp = strchr(cp + 1, '.'); if (cp != NULL) return error; for (cp = name, i = 0; i < nmlen; i++, cp++) if (strchr(badchars83, *cp) != NULL) return error; } for (cp = name, i = 0; i < nmlen; i++, cp++) if (strchr(badchars, *cp) != NULL) return error; return 0; } /* * Things go even weird without fixed inode numbers... */ int smbfs_lookup(struct vop_lookup_args *ap) { struct componentname *cnp = ap->a_cnp; struct thread *td = curthread; struct vnode *dvp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; struct vnode *vp; struct smbmount *smp; struct mount *mp = dvp->v_mount; struct smbnode *dnp; struct smbfattr fattr, *fap; struct smb_cred *scred; char *name = cnp->cn_nameptr; uint64_t flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; int nmlen = cnp->cn_namelen; int error, islastcn, isdot; int killit; SMBVDEBUG("\n"); if (dvp->v_type != VDIR) return ENOTDIR; if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { SMBFSERR("invalid '..'\n"); return EIO; } islastcn = flags & ISLASTCN; if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) return EROFS; error = vn_dir_check_exec(dvp, cnp); if (error != 0) return error; smp = VFSTOSMBFS(mp); dnp = VTOSMB(dvp); isdot = (nmlen == 1 && name[0] == '.'); error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); if (error) return ENOENT; error = cache_lookup(dvp, vpp, cnp, NULL, NULL); SMBVDEBUG("cache_lookup returned %d\n", error); if (error > 0) return error; if (error) { /* name was found */ struct vattr vattr; killit = 0; vp = *vpp; error = VOP_GETATTR(vp, &vattr, cnp->cn_cred); /* * If the file type on the server is inconsistent * with what it was when we created the vnode, * kill the bogus vnode now and fall through to * the code below to create a new one with the * right type. */ if (error == 0 && ((vp->v_type == VDIR && (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || (vp->v_type == VREG && (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) killit = 1; else if (error == 0 /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { SMBVDEBUG("use cached vnode\n"); return (0); } cache_purge(vp); /* * XXX This is not quite right, if '.' is * inconsistent, we really need to start the lookup * all over again. Hopefully there is some other * guarantee that prevents this case from happening. */ if (killit && vp != dvp) vgone(vp); if (vp != dvp) vput(vp); else vrele(vp); *vpp = NULL; } /* * entry is not in the cache or has been expired */ error = 0; *vpp = NULL; scred = smbfs_malloc_scred(); smb_makescred(scred, td, cnp->cn_cred); fap = &fattr; if (flags & ISDOTDOT) { /* * In the DOTDOT case, don't go over-the-wire * in order to request attributes. We already * know it's a directory and subsequent call to * smbfs_getattr() will restore consistency. * */ SMBVDEBUG("smbfs_smb_lookup: dotdot\n"); } else if (isdot) { error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); } else { error = smbfs_smb_lookup(dnp, name, nmlen, fap, scred); SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); } if (error && error != ENOENT) goto out; if (error) { /* entry not found */ /* * Handle RENAME or CREATE case... */ if ((nameiop == CREATE || nameiop == RENAME) && islastcn) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); if (error) goto out; error = EJUSTRETURN; goto out; } error = ENOENT; goto out; }/* else { SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); }*/ /* * handle DELETE case ... */ if (nameiop == DELETE && islastcn) { /* delete last component */ error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); if (error) goto out; if (isdot) { - VREF(dvp); + vref(dvp); *vpp = dvp; goto out; } error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); if (error) goto out; *vpp = vp; goto out; } if (nameiop == RENAME && islastcn) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); if (error) goto out; if (isdot) { error = EISDIR; goto out; } error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); if (error) goto out; *vpp = vp; goto out; } if (flags & ISDOTDOT) { mp = dvp->v_mount; error = vfs_busy(mp, MBF_NOWAIT); if (error != 0) { vfs_ref(mp); VOP_UNLOCK(dvp); error = vfs_busy(mp, 0); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); vfs_rel(mp); if (error) { error = ENOENT; goto out; } if (VN_IS_DOOMED(dvp)) { vfs_unbusy(mp); error = ENOENT; goto out; } } VOP_UNLOCK(dvp); error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); vfs_unbusy(mp); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); if (VN_IS_DOOMED(dvp)) { if (error == 0) vput(vp); error = ENOENT; } if (error) goto out; *vpp = vp; } else if (isdot) { vref(dvp); *vpp = dvp; } else { error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); if (error) goto out; *vpp = vp; SMBVDEBUG("lookup: getnewvp!\n"); } if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { /* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ cache_enter(dvp, *vpp, cnp); } out: smbfs_free_scred(scred); return (error); } diff --git a/sys/fs/tarfs/tarfs_vnops.c b/sys/fs/tarfs/tarfs_vnops.c index b0921909b3b4..70fd7a441d81 100644 --- a/sys/fs/tarfs/tarfs_vnops.c +++ b/sys/fs/tarfs/tarfs_vnops.c @@ -1,705 +1,705 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2013 Juniper Networks, Inc. * Copyright (c) 2022-2023 Klara, Inc. * * 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_tarfs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include static int tarfs_open(struct vop_open_args *ap) { struct tarfs_node *tnp; struct vnode *vp; vp = ap->a_vp; MPASS(VOP_ISLOCKED(vp)); tnp = VP_TO_TARFS_NODE(vp); TARFS_DPF(VNODE, "%s(%p=%s, %o)\n", __func__, tnp, tnp->name, ap->a_mode); if (vp->v_type != VREG && vp->v_type != VDIR) return (EOPNOTSUPP); vnode_create_vobject(vp, tnp->size, ap->a_td); return (0); } static int tarfs_close(struct vop_close_args *ap) { #ifdef TARFS_DEBUG struct tarfs_node *tnp; struct vnode *vp; vp = ap->a_vp; MPASS(VOP_ISLOCKED(vp)); tnp = VP_TO_TARFS_NODE(vp); TARFS_DPF(VNODE, "%s(%p=%s)\n", __func__, tnp, tnp->name); #else (void)ap; #endif return (0); } static int tarfs_access(struct vop_access_args *ap) { struct tarfs_node *tnp; struct vnode *vp; accmode_t accmode; struct ucred *cred; int error; vp = ap->a_vp; accmode = ap->a_accmode; cred = ap->a_cred; MPASS(VOP_ISLOCKED(vp)); tnp = VP_TO_TARFS_NODE(vp); TARFS_DPF(VNODE, "%s(%p=%s, %o)\n", __func__, tnp, tnp->name, accmode); switch (vp->v_type) { case VDIR: case VLNK: case VREG: if ((accmode & VWRITE) != 0) return (EROFS); break; case VBLK: case VCHR: case VFIFO: break; default: return (EINVAL); } if ((accmode & VWRITE) != 0) return (EPERM); error = vaccess(vp->v_type, tnp->mode, tnp->uid, tnp->gid, accmode, cred); return (error); } static int tarfs_bmap(struct vop_bmap_args *ap) { struct tarfs_node *tnp; struct vnode *vp; off_t off; uint64_t iosize; int ra, rb, rmax; vp = ap->a_vp; iosize = vp->v_mount->mnt_stat.f_iosize; if (ap->a_bop != NULL) *ap->a_bop = &vp->v_bufobj; if (ap->a_bnp != NULL) *ap->a_bnp = ap->a_bn * btodb(iosize); if (ap->a_runp == NULL) return (0); tnp = VP_TO_TARFS_NODE(vp); off = ap->a_bn * iosize; ra = rb = 0; for (u_int i = 0; i < tnp->nblk; i++) { off_t bs, be; bs = tnp->blk[i].o; be = tnp->blk[i].o + tnp->blk[i].l; if (off > be) continue; else if (off < bs) { /* We're in a hole. */ ra = bs - off < iosize ? 0 : howmany(bs - (off + iosize), iosize); rb = howmany(off - (i == 0 ? 0 : tnp->blk[i - 1].o + tnp->blk[i - 1].l), iosize); break; } else { /* We'll be reading from the backing file. */ ra = be - off < iosize ? 0 : howmany(be - (off + iosize), iosize); rb = howmany(off - bs, iosize); break; } } rmax = vp->v_mount->mnt_iosize_max / iosize - 1; *ap->a_runp = imin(ra, rmax); if (ap->a_runb != NULL) *ap->a_runb = imin(rb, rmax); return (0); } static int tarfs_getattr(struct vop_getattr_args *ap) { struct tarfs_node *tnp; struct vnode *vp; struct vattr *vap; vp = ap->a_vp; vap = ap->a_vap; tnp = VP_TO_TARFS_NODE(vp); TARFS_DPF(VNODE, "%s(%p=%s)\n", __func__, tnp, tnp->name); vap->va_type = vp->v_type; vap->va_mode = tnp->mode; vap->va_nlink = tnp->nlink; vap->va_gid = tnp->gid; vap->va_uid = tnp->uid; vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; vap->va_fileid = tnp->ino; vap->va_size = tnp->size; vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; vap->va_atime = tnp->atime; vap->va_ctime = tnp->ctime; vap->va_mtime = tnp->mtime; vap->va_birthtime = tnp->birthtime; vap->va_gen = tnp->gen; vap->va_flags = tnp->flags; vap->va_rdev = VN_ISDEV(vp) ? tnp->rdev : NODEV; vap->va_bytes = round_page(tnp->physize); vap->va_filerev = 0; return (0); } static int tarfs_lookup(struct vop_cachedlookup_args *ap) { struct tarfs_mount *tmp; struct tarfs_node *dirnode, *parent, *tnp; struct componentname *cnp; struct vnode *dvp, **vpp; #ifdef TARFS_DEBUG struct vnode *vp; #endif int error; dvp = ap->a_dvp; vpp = ap->a_vpp; cnp = ap->a_cnp; *vpp = NULL; dirnode = VP_TO_TARFS_NODE(dvp); parent = dirnode->parent; tmp = dirnode->tmp; tnp = NULL; TARFS_DPF(LOOKUP, "%s(%p=%s, %.*s)\n", __func__, dirnode, dirnode->name, (int)cnp->cn_namelen, cnp->cn_nameptr); error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, curthread); if (error != 0) return (error); if (cnp->cn_flags & ISDOTDOT) { /* Do not allow .. on the root node */ if (parent == NULL || parent == dirnode) return (ENOENT); /* Allocate a new vnode on the matching entry */ error = vn_vget_ino(dvp, parent->ino, cnp->cn_lkflags, vpp); if (error != 0) return (error); } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { - VREF(dvp); + vref(dvp); *vpp = dvp; #ifdef TARFS_DEBUG } else if (dirnode == dirnode->tmp->root && (vp = dirnode->tmp->znode) != NULL && cnp->cn_namelen == TARFS_ZIO_NAMELEN && memcmp(cnp->cn_nameptr, TARFS_ZIO_NAME, TARFS_ZIO_NAMELEN) == 0) { error = vn_lock(vp, cnp->cn_lkflags); if (error != 0) return (error); vref(vp); *vpp = vp; return (0); #endif } else { tnp = tarfs_lookup_node(dirnode, NULL, cnp); if (tnp == NULL) { TARFS_DPF(LOOKUP, "%s(%p=%s, %.*s): file not found\n", __func__, dirnode, dirnode->name, (int)cnp->cn_namelen, cnp->cn_nameptr); return (ENOENT); } if ((cnp->cn_flags & ISLASTCN) == 0 && (tnp->type != VDIR && tnp->type != VLNK)) return (ENOTDIR); error = VFS_VGET(tmp->vfs, tnp->ino, cnp->cn_lkflags, vpp); if (error != 0) return (error); } #ifdef TARFS_DEBUG if (tnp == NULL) tnp = VP_TO_TARFS_NODE(*vpp); TARFS_DPF(LOOKUP, "%s: found vnode %p, tarfs_node %p\n", __func__, *vpp, tnp); #endif /* TARFS_DEBUG */ /* Store the result of the cache if MAKEENTRY is specified in flags */ if ((cnp->cn_flags & MAKEENTRY) != 0 && cnp->cn_nameiop != CREATE) cache_enter(dvp, *vpp, cnp); return (error); } static int tarfs_readdir(struct vop_readdir_args *ap) { struct dirent cde = { }; struct tarfs_node *current, *tnp; struct vnode *vp; struct uio *uio; int *eofflag; uint64_t **cookies; int *ncookies; off_t off; u_int idx, ndirents; int error; vp = ap->a_vp; uio = ap->a_uio; eofflag = ap->a_eofflag; cookies = ap->a_cookies; ncookies = ap->a_ncookies; if (vp->v_type != VDIR) return (ENOTDIR); tnp = VP_TO_TARFS_NODE(vp); off = uio->uio_offset; current = NULL; ndirents = 0; TARFS_DPF(VNODE, "%s(%p=%s, %zu, %zd)\n", __func__, tnp, tnp->name, uio->uio_offset, uio->uio_resid); if (uio->uio_offset == TARFS_COOKIE_EOF) { if (eofflag != NULL) { TARFS_DPF(VNODE, "%s: Setting EOF flag\n", __func__); *eofflag = 1; } TARFS_DPF(VNODE, "%s: EOF\n", __func__); return (0); } if (uio->uio_offset == TARFS_COOKIE_DOT) { TARFS_DPF(VNODE, "%s: Generating . entry\n", __func__); /* fake . entry */ cde.d_fileno = tnp->ino; cde.d_type = DT_DIR; cde.d_namlen = 1; cde.d_name[0] = '.'; cde.d_name[1] = '\0'; cde.d_reclen = GENERIC_DIRSIZ(&cde); if (cde.d_reclen > uio->uio_resid) goto full; dirent_terminate(&cde); error = uiomove(&cde, cde.d_reclen, uio); if (error) return (error); /* next is .. */ uio->uio_offset = TARFS_COOKIE_DOTDOT; ndirents++; } if (uio->uio_offset == TARFS_COOKIE_DOTDOT) { TARFS_DPF(VNODE, "%s: Generating .. entry\n", __func__); /* fake .. entry */ MPASS(tnp->parent != NULL); TARFS_NODE_LOCK(tnp->parent); cde.d_fileno = tnp->parent->ino; TARFS_NODE_UNLOCK(tnp->parent); cde.d_type = DT_DIR; cde.d_namlen = 2; cde.d_name[0] = '.'; cde.d_name[1] = '.'; cde.d_name[2] = '\0'; cde.d_reclen = GENERIC_DIRSIZ(&cde); if (cde.d_reclen > uio->uio_resid) goto full; dirent_terminate(&cde); error = uiomove(&cde, cde.d_reclen, uio); if (error) return (error); /* next is first child */ current = TAILQ_FIRST(&tnp->dir.dirhead); if (current == NULL) goto done; uio->uio_offset = current->ino; TARFS_DPF(VNODE, "%s: [%u] setting current node to %p=%s\n", __func__, ndirents, current, current->name); ndirents++; } /* resuming previous call */ if (current == NULL) { current = tarfs_lookup_dir(tnp, uio->uio_offset); if (current == NULL) { error = EINVAL; goto done; } uio->uio_offset = current->ino; TARFS_DPF(VNODE, "%s: [%u] setting current node to %p=%s\n", __func__, ndirents, current, current->name); } for (;;) { cde.d_fileno = current->ino; switch (current->type) { case VBLK: cde.d_type = DT_BLK; break; case VCHR: cde.d_type = DT_CHR; break; case VDIR: cde.d_type = DT_DIR; break; case VFIFO: cde.d_type = DT_FIFO; break; case VLNK: cde.d_type = DT_LNK; break; case VREG: cde.d_type = DT_REG; break; default: panic("%s: tarfs_node %p, type %d\n", __func__, current, current->type); } cde.d_namlen = current->namelen; MPASS(tnp->namelen < sizeof(cde.d_name)); (void)memcpy(cde.d_name, current->name, current->namelen); cde.d_name[current->namelen] = '\0'; cde.d_reclen = GENERIC_DIRSIZ(&cde); if (cde.d_reclen > uio->uio_resid) goto full; dirent_terminate(&cde); error = uiomove(&cde, cde.d_reclen, uio); if (error != 0) goto done; ndirents++; /* next sibling */ current = TAILQ_NEXT(current, dirents); if (current == NULL) goto done; uio->uio_offset = current->ino; TARFS_DPF(VNODE, "%s: [%u] setting current node to %p=%s\n", __func__, ndirents, current, current->name); } full: if (cde.d_reclen > uio->uio_resid) { TARFS_DPF(VNODE, "%s: out of space, returning\n", __func__); error = (ndirents == 0) ? EINVAL : 0; } done: TARFS_DPF(VNODE, "%s: %u entries written\n", __func__, ndirents); TARFS_DPF(VNODE, "%s: saving cache information\n", __func__); if (current == NULL) { uio->uio_offset = TARFS_COOKIE_EOF; tnp->dir.lastcookie = 0; tnp->dir.lastnode = NULL; } else { tnp->dir.lastcookie = current->ino; tnp->dir.lastnode = current; } if (eofflag != NULL) { TARFS_DPF(VNODE, "%s: Setting EOF flag\n", __func__); *eofflag = (error == 0 && current == NULL); } /* Update for NFS */ if (error == 0 && cookies != NULL && ncookies != NULL) { TARFS_DPF(VNODE, "%s: Updating NFS cookies\n", __func__); current = NULL; *cookies = malloc(ndirents * sizeof(off_t), M_TEMP, M_WAITOK); *ncookies = ndirents; for (idx = 0; idx < ndirents; idx++) { if (off == TARFS_COOKIE_DOT) off = TARFS_COOKIE_DOTDOT; else { if (off == TARFS_COOKIE_DOTDOT) { current = TAILQ_FIRST(&tnp->dir.dirhead); } else if (current != NULL) { current = TAILQ_NEXT(current, dirents); } else { current = tarfs_lookup_dir(tnp, off); current = TAILQ_NEXT(current, dirents); } if (current == NULL) off = TARFS_COOKIE_EOF; else off = current->ino; } TARFS_DPF(VNODE, "%s: [%u] offset %zu\n", __func__, idx, off); (*cookies)[idx] = off; } MPASS(uio->uio_offset == off); } return (error); } static int tarfs_read(struct vop_read_args *ap) { struct tarfs_node *tnp; struct uio *uiop; struct vnode *vp; size_t len; off_t resid; int error; uiop = ap->a_uio; vp = ap->a_vp; if (VN_ISDEV(vp)) return (EOPNOTSUPP); if (vp->v_type != VREG) return (EISDIR); if (uiop->uio_offset < 0) return (EINVAL); tnp = VP_TO_TARFS_NODE(vp); error = 0; TARFS_DPF(VNODE, "%s(%p=%s, %zu, %zd)\n", __func__, tnp, tnp->name, uiop->uio_offset, uiop->uio_resid); while ((resid = uiop->uio_resid) > 0) { if (tnp->size <= uiop->uio_offset) break; len = MIN(tnp->size - uiop->uio_offset, resid); if (len == 0) break; error = tarfs_read_file(tnp, len, uiop); if (error != 0 || resid == uiop->uio_resid) break; } return (error); } static int tarfs_readlink(struct vop_readlink_args *ap) { struct tarfs_node *tnp; struct uio *uiop; struct vnode *vp; int error; uiop = ap->a_uio; vp = ap->a_vp; MPASS(uiop->uio_offset == 0); MPASS(vp->v_type == VLNK); tnp = VP_TO_TARFS_NODE(vp); TARFS_DPF(VNODE, "%s(%p=%s)\n", __func__, tnp, tnp->name); error = uiomove(tnp->link.name, MIN(tnp->size, uiop->uio_resid), uiop); return (error); } static int tarfs_reclaim(struct vop_reclaim_args *ap) { struct tarfs_node *tnp; struct vnode *vp; vp = ap->a_vp; tnp = VP_TO_TARFS_NODE(vp); vfs_hash_remove(vp); TARFS_NODE_LOCK(tnp); tnp->vnode = NULL; vp->v_data = NULL; TARFS_NODE_UNLOCK(tnp); return (0); } static int tarfs_print(struct vop_print_args *ap) { struct tarfs_node *tnp; struct vnode *vp; vp = ap->a_vp; tnp = VP_TO_TARFS_NODE(vp); printf("tag tarfs, tarfs_node %p, links %lu\n", tnp, (unsigned long)tnp->nlink); printf("\tmode 0%o, owner %d, group %d, size %zd\n", tnp->mode, tnp->uid, tnp->gid, tnp->size); if (vp->v_type == VFIFO) fifo_printinfo(vp); printf("\n"); return (0); } static int tarfs_strategy(struct vop_strategy_args *ap) { struct uio auio; struct iovec iov; struct tarfs_node *tnp; struct buf *bp; off_t off; size_t len; int error; tnp = VP_TO_TARFS_NODE(ap->a_vp); bp = ap->a_bp; MPASS(bp->b_iocmd == BIO_READ); MPASS(bp->b_iooffset >= 0); MPASS(bp->b_bcount > 0); MPASS(bp->b_bufsize >= bp->b_bcount); TARFS_DPF(VNODE, "%s(%p=%s, %zu, %ld/%ld)\n", __func__, tnp, tnp->name, (size_t)bp->b_iooffset, bp->b_bcount, bp->b_bufsize); iov.iov_base = bp->b_data; iov.iov_len = bp->b_bcount; off = bp->b_iooffset; len = bp->b_bcount; bp->b_resid = len; if (off > tnp->size) { /* XXX read beyond EOF - figure out correct handling */ error = EIO; goto out; } if (off + len > tnp->size) { /* clip to file length */ len = tnp->size - off; } auio.uio_iov = &iov; auio.uio_iovcnt = 1; auio.uio_offset = off; auio.uio_resid = len; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_READ; auio.uio_td = curthread; error = tarfs_read_file(tnp, len, &auio); bp->b_resid -= len - auio.uio_resid; out: if (error != 0) { bp->b_ioflags |= BIO_ERROR; bp->b_error = error; } bp->b_flags |= B_DONE; return (0); } static int tarfs_vptofh(struct vop_vptofh_args *ap) { struct tarfs_fid *tfp; struct tarfs_node *tnp; _Static_assert(sizeof(struct tarfs_fid) <= sizeof(struct fid), "struct tarfs_fid cannot be larger than struct fid"); tfp = (struct tarfs_fid *)ap->a_fhp; tnp = VP_TO_TARFS_NODE(ap->a_vp); tfp->len = sizeof(struct tarfs_fid); tfp->ino = tnp->ino; tfp->gen = tnp->gen; return (0); } struct vop_vector tarfs_vnodeops = { .vop_default = &default_vnodeops, .vop_access = tarfs_access, .vop_bmap = tarfs_bmap, .vop_cachedlookup = tarfs_lookup, .vop_close = tarfs_close, .vop_getattr = tarfs_getattr, .vop_lookup = vfs_cache_lookup, .vop_open = tarfs_open, .vop_print = tarfs_print, .vop_read = tarfs_read, .vop_readdir = tarfs_readdir, .vop_readlink = tarfs_readlink, .vop_reclaim = tarfs_reclaim, .vop_strategy = tarfs_strategy, .vop_vptofh = tarfs_vptofh, }; VFS_VOP_VECTOR_REGISTER(tarfs_vnodeops); diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 312d2e717e63..5082ee1ebdd0 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -1,2228 +1,2228 @@ /* $NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Julio M. Merino Vidal, developed as part of Google's Summer of Code * 2005 program. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ /* * tmpfs vnode interface. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SYSCTL_DECL(_vfs_tmpfs); VFS_SMR_DECLARE; static volatile int tmpfs_rename_restarts; SYSCTL_INT(_vfs_tmpfs, OID_AUTO, rename_restarts, CTLFLAG_RD, __DEVOLATILE(int *, &tmpfs_rename_restarts), 0, "Times rename had to restart due to lock contention"); MALLOC_DEFINE(M_TMPFSEA, "tmpfs extattr", "tmpfs extattr structure"); static int tmpfs_vn_get_ino_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **rvp) { return (tmpfs_alloc_vp(mp, arg, lkflags, rvp)); } static int tmpfs_lookup1(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) { struct tmpfs_dirent *de; struct tmpfs_node *dnode, *pnode; struct tmpfs_mount *tm; int error; /* Caller assumes responsibility for ensuring access (VEXEC). */ dnode = VP_TO_TMPFS_DIR(dvp); *vpp = NULL; /* We cannot be requesting the parent directory of the root node. */ MPASS(IMPLIES(dnode->tn_type == VDIR && dnode->tn_dir.tn_parent == dnode, !(cnp->cn_flags & ISDOTDOT))); TMPFS_ASSERT_LOCKED(dnode); if (dnode->tn_dir.tn_parent == NULL) { error = ENOENT; goto out; } if (cnp->cn_flags & ISDOTDOT) { tm = VFS_TO_TMPFS(dvp->v_mount); pnode = dnode->tn_dir.tn_parent; tmpfs_ref_node(pnode); error = vn_vget_ino_gen(dvp, tmpfs_vn_get_ino_alloc, pnode, cnp->cn_lkflags, vpp); tmpfs_free_node(tm, pnode); if (error != 0) goto out; } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { - VREF(dvp); + vref(dvp); *vpp = dvp; error = 0; } else { de = tmpfs_dir_lookup(dnode, NULL, cnp); if (de != NULL && de->td_node == NULL) cnp->cn_flags |= ISWHITEOUT; if (de == NULL || de->td_node == NULL) { /* * The entry was not found in the directory. * This is OK if we are creating or renaming an * entry and are working on the last component of * the path name. */ if ((cnp->cn_flags & ISLASTCN) && (cnp->cn_nameiop == CREATE || \ cnp->cn_nameiop == RENAME || (cnp->cn_nameiop == DELETE && cnp->cn_flags & DOWHITEOUT && cnp->cn_flags & ISWHITEOUT))) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, curthread); if (error != 0) goto out; error = EJUSTRETURN; } else error = ENOENT; } else { struct tmpfs_node *tnode; /* * The entry was found, so get its associated * tmpfs_node. */ tnode = de->td_node; /* * If we are not at the last path component and * found a non-directory or non-link entry (which * may itself be pointing to a directory), raise * an error. */ if ((tnode->tn_type != VDIR && tnode->tn_type != VLNK) && !(cnp->cn_flags & ISLASTCN)) { error = ENOTDIR; goto out; } /* * If we are deleting or renaming the entry, keep * track of its tmpfs_dirent so that it can be * easily deleted later. */ if ((cnp->cn_flags & ISLASTCN) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, curthread); if (error != 0) goto out; /* Allocate a new vnode on the matching entry. */ error = tmpfs_alloc_vp(dvp->v_mount, tnode, cnp->cn_lkflags, vpp); if (error != 0) goto out; if ((dnode->tn_mode & S_ISTXT) && VOP_ACCESS(dvp, VADMIN, cnp->cn_cred, curthread) && VOP_ACCESS(*vpp, VADMIN, cnp->cn_cred, curthread)) { error = EPERM; vput(*vpp); *vpp = NULL; goto out; } } else { error = tmpfs_alloc_vp(dvp->v_mount, tnode, cnp->cn_lkflags, vpp); if (error != 0) goto out; } } } /* * Store the result of this lookup in the cache. Avoid this if the * request was for creation, as it does not improve timings on * emprical tests. */ if ((cnp->cn_flags & MAKEENTRY) != 0 && tmpfs_use_nc(dvp)) cache_enter(dvp, *vpp, cnp); out: #ifdef INVARIANTS /* * If there were no errors, *vpp cannot be null and it must be * locked. */ if (error == 0) { MPASS(*vpp != NULL); ASSERT_VOP_LOCKED(*vpp, __func__); } else { MPASS(*vpp == NULL); } #endif return (error); } static int tmpfs_cached_lookup(struct vop_cachedlookup_args *v) { return (tmpfs_lookup1(v->a_dvp, v->a_vpp, v->a_cnp)); } static int tmpfs_lookup(struct vop_lookup_args *v) { struct vnode *dvp = v->a_dvp; struct vnode **vpp = v->a_vpp; struct componentname *cnp = v->a_cnp; int error; /* Check accessibility of requested node as a first step. */ error = vn_dir_check_exec(dvp, cnp); if (error != 0) return (error); return (tmpfs_lookup1(dvp, vpp, cnp)); } static int tmpfs_create(struct vop_create_args *v) { struct vnode *dvp = v->a_dvp; struct vnode **vpp = v->a_vpp; struct componentname *cnp = v->a_cnp; struct vattr *vap = v->a_vap; int error; MPASS(vap->va_type == VREG || vap->va_type == VSOCK); error = tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); if (error == 0 && (cnp->cn_flags & MAKEENTRY) != 0 && tmpfs_use_nc(dvp)) cache_enter(dvp, *vpp, cnp); return (error); } static int tmpfs_mknod(struct vop_mknod_args *v) { struct vnode *dvp = v->a_dvp; struct vnode **vpp = v->a_vpp; struct componentname *cnp = v->a_cnp; struct vattr *vap = v->a_vap; if (!VATTR_ISDEV(vap) && vap->va_type != VFIFO) return (EINVAL); return (tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL)); } struct fileops tmpfs_fnops; static int tmpfs_open(struct vop_open_args *v) { struct vnode *vp; struct tmpfs_node *node; struct file *fp; int error, mode; vp = v->a_vp; mode = v->a_mode; node = VP_TO_TMPFS_NODE(vp); /* * The file is still active but all its names have been removed * (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as * it is about to die. */ if (node->tn_links < 1) return (ENOENT); /* If the file is marked append-only, deny write requests. */ if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE) error = EPERM; else { error = 0; /* For regular files, the call below is nop. */ KASSERT(vp->v_type != VREG || (node->tn_reg.tn_aobj->flags & OBJ_DEAD) == 0, ("dead object")); vnode_create_vobject(vp, node->tn_size, v->a_td); } fp = v->a_fp; MPASS(fp == NULL || fp->f_data == NULL); if (error == 0 && fp != NULL && vp->v_type == VREG) { tmpfs_ref_node(node); finit_vnode(fp, mode, node, &tmpfs_fnops); } return (error); } static int tmpfs_close(struct vop_close_args *v) { struct vnode *vp = v->a_vp; /* Update node times. */ tmpfs_update(vp); return (0); } int tmpfs_fo_close(struct file *fp, struct thread *td) { struct tmpfs_node *node; node = fp->f_data; if (node != NULL) { MPASS(node->tn_type == VREG); tmpfs_free_node(node->tn_reg.tn_tmp, node); } return (vnops.fo_close(fp, td)); } /* * VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see * the comment above cache_fplookup for details. */ int tmpfs_fplookup_vexec(struct vop_fplookup_vexec_args *v) { struct vnode *vp; struct tmpfs_node *node; struct ucred *cred; mode_t all_x, mode; vp = v->a_vp; node = VP_TO_TMPFS_NODE_SMR(vp); if (__predict_false(node == NULL)) return (EAGAIN); all_x = S_IXUSR | S_IXGRP | S_IXOTH; mode = atomic_load_short(&node->tn_mode); if (__predict_true((mode & all_x) == all_x)) return (0); cred = v->a_cred; return (vaccess_vexec_smr(mode, node->tn_uid, node->tn_gid, cred)); } static int tmpfs_access_locked(struct vnode *vp, struct tmpfs_node *node, accmode_t accmode, struct ucred *cred) { #ifdef INVARIANTS if (!mtx_owned(TMPFS_NODE_MTX(node))) { ASSERT_VOP_LOCKED(vp, "tmpfs_access_locked needs locked vnode or node"); } #endif if ((accmode & VWRITE) != 0 && (node->tn_flags & IMMUTABLE) != 0) return (EPERM); return (vaccess(vp->v_type, node->tn_mode, node->tn_uid, node->tn_gid, accmode, cred)); } int tmpfs_access(struct vop_access_args *v) { struct vnode *vp = v->a_vp; struct ucred *cred = v->a_cred; struct tmpfs_node *node = VP_TO_TMPFS_NODE(vp); mode_t all_x = S_IXUSR | S_IXGRP | S_IXOTH; accmode_t accmode = v->a_accmode; /* * Common case path lookup. */ if (__predict_true(accmode == VEXEC && (node->tn_mode & all_x) == all_x)) return (0); switch (vp->v_type) { case VDIR: /* FALLTHROUGH */ case VLNK: /* FALLTHROUGH */ case VREG: if ((accmode & VWRITE) != 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) != 0) return (EROFS); break; case VBLK: /* FALLTHROUGH */ case VCHR: /* FALLTHROUGH */ case VSOCK: /* FALLTHROUGH */ case VFIFO: break; default: return (EINVAL); } return (tmpfs_access_locked(vp, node, accmode, cred)); } int tmpfs_stat(struct vop_stat_args *v) { struct vnode *vp = v->a_vp; struct stat *sb = v->a_sb; struct tmpfs_node *node; int error; node = VP_TO_TMPFS_NODE(vp); tmpfs_update_getattr(vp); error = vop_stat_helper_pre(v); if (__predict_false(error)) return (error); sb->st_dev = vp->v_mount->mnt_stat.f_fsid.val[0]; sb->st_ino = node->tn_id; sb->st_mode = node->tn_mode | VTTOIF(vp->v_type); sb->st_nlink = node->tn_links; sb->st_uid = node->tn_uid; sb->st_gid = node->tn_gid; 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; sb->st_mtim.tv_sec = node->tn_mtime.tv_sec; sb->st_mtim.tv_nsec = node->tn_mtime.tv_nsec; sb->st_ctim.tv_sec = node->tn_ctime.tv_sec; sb->st_ctim.tv_nsec = node->tn_ctime.tv_nsec; sb->st_birthtim.tv_sec = node->tn_birthtime.tv_sec; sb->st_birthtim.tv_nsec = node->tn_birthtime.tv_nsec; sb->st_blksize = PAGE_SIZE; sb->st_flags = node->tn_flags; sb->st_gen = node->tn_gen; sb->st_filerev = 0; if (vp->v_type == VREG) { #ifdef __ILP32__ vm_object_t obj = node->tn_reg.tn_aobj; /* Handle torn read */ VM_OBJECT_RLOCK(obj); #endif sb->st_blocks = ptoa(node->tn_reg.tn_pages); #ifdef __ILP32__ VM_OBJECT_RUNLOCK(obj); #endif } else { sb->st_blocks = node->tn_size; } sb->st_blocks /= S_BLKSIZE; return (vop_stat_helper_post(v, error)); } int tmpfs_getattr(struct vop_getattr_args *v) { struct vnode *vp = v->a_vp; struct vattr *vap = v->a_vap; struct tmpfs_node *node; node = VP_TO_TMPFS_NODE(vp); tmpfs_update_getattr(vp); vap->va_type = vp->v_type; vap->va_mode = node->tn_mode; vap->va_nlink = node->tn_links; vap->va_uid = node->tn_uid; vap->va_gid = node->tn_gid; vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; vap->va_fileid = node->tn_id; vap->va_size = node->tn_size; vap->va_blocksize = PAGE_SIZE; vap->va_atime = node->tn_atime; vap->va_mtime = node->tn_mtime; vap->va_ctime = node->tn_ctime; vap->va_birthtime = node->tn_birthtime; vap->va_gen = node->tn_gen; vap->va_flags = node->tn_flags; 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; VM_OBJECT_RLOCK(obj); #endif vap->va_bytes = ptoa(node->tn_reg.tn_pages); #ifdef __ILP32__ VM_OBJECT_RUNLOCK(obj); #endif } else { vap->va_bytes = node->tn_size; } vap->va_filerev = 0; return (0); } int tmpfs_setattr(struct vop_setattr_args *v) { struct vnode *vp = v->a_vp; struct vattr *vap = v->a_vap; struct ucred *cred = v->a_cred; struct thread *td = curthread; int error; ASSERT_VOP_IN_SEQC(vp); error = 0; /* Abort if any unsettable attribute is given. */ if (vap->va_type != VNON || vap->va_nlink != VNOVAL || vap->va_fsid != VNOVAL || vap->va_fileid != VNOVAL || vap->va_blocksize != VNOVAL || vap->va_gen != VNOVAL || vap->va_rdev != VNOVAL || vap->va_bytes != VNOVAL) error = EINVAL; if (error == 0 && (vap->va_flags != VNOVAL)) error = tmpfs_chflags(vp, vap->va_flags, cred, td); if (error == 0 && (vap->va_size != VNOVAL)) error = tmpfs_chsize(vp, vap->va_size, cred, td); if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td); if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) error = tmpfs_chmod(vp, vap->va_mode, cred, td); if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL && vap->va_atime.tv_nsec != VNOVAL) || (vap->va_mtime.tv_sec != VNOVAL && vap->va_mtime.tv_nsec != VNOVAL) || (vap->va_birthtime.tv_sec != VNOVAL && vap->va_birthtime.tv_nsec != VNOVAL))) error = tmpfs_chtimes(vp, vap, cred, td); /* * Update the node times. We give preference to the error codes * generated by this function rather than the ones that may arise * from tmpfs_update. */ tmpfs_update(vp); return (error); } static int tmpfs_read(struct vop_read_args *v) { struct vnode *vp; struct uio *uio; struct tmpfs_node *node; vp = v->a_vp; if (vp->v_type != VREG) return (EISDIR); uio = v->a_uio; if (uio->uio_offset < 0) return (EINVAL); node = VP_TO_TMPFS_NODE(vp); tmpfs_set_accessed(VFS_TO_TMPFS(vp->v_mount), node); return (uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio)); } static int tmpfs_read_pgcache(struct vop_read_pgcache_args *v) { struct vnode *vp; struct tmpfs_node *node; vm_object_t object; off_t size; int error; vp = v->a_vp; VNPASS((vn_irflag_read(vp) & VIRF_PGREAD) != 0, vp); if (v->a_uio->uio_offset < 0) return (EINVAL); error = EJUSTRETURN; vfs_smr_enter(); node = VP_TO_TMPFS_NODE_SMR(vp); if (node == NULL) goto out_smr; MPASS(node->tn_type == VREG); MPASS(node->tn_refcount >= 1); object = node->tn_reg.tn_aobj; if (object == NULL) goto out_smr; MPASS(object->type == tmpfs_pager_type); MPASS((object->flags & (OBJ_ANON | OBJ_DEAD | OBJ_SWAP)) == OBJ_SWAP); if (!VN_IS_DOOMED(vp)) { /* size cannot become shorter due to rangelock. */ size = node->tn_size; tmpfs_set_accessed(node->tn_reg.tn_tmp, node); vfs_smr_exit(); error = uiomove_object(object, size, v->a_uio); return (error); } out_smr: vfs_smr_exit(); return (error); } static int tmpfs_write(struct vop_write_args *v) { struct vnode *vp; struct uio *uio; struct tmpfs_node *node; off_t oldsize; ssize_t r; int error, ioflag; mode_t newmode; vp = v->a_vp; uio = v->a_uio; ioflag = v->a_ioflag; error = 0; node = VP_TO_TMPFS_NODE(vp); oldsize = node->tn_size; if (uio->uio_offset < 0 || vp->v_type != VREG) return (EINVAL); if (uio->uio_resid == 0) return (0); if (ioflag & IO_APPEND) uio->uio_offset = node->tn_size; error = vn_rlimit_fsizex(vp, uio, VFS_TO_TMPFS(vp->v_mount)-> tm_maxfilesize, &r, uio->uio_td); if (error != 0) { vn_rlimit_fsizex_res(uio, r); return (error); } if (uio->uio_offset + uio->uio_resid > node->tn_size) { error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid, FALSE); if (error != 0) goto out; } error = uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio); node->tn_status |= TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED; node->tn_accessed = true; if (node->tn_mode & (S_ISUID | S_ISGID)) { if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID)) { newmode = node->tn_mode & ~(S_ISUID | S_ISGID); vn_seqc_write_begin(vp); atomic_store_short(&node->tn_mode, newmode); vn_seqc_write_end(vp); } } if (error != 0) (void)tmpfs_reg_resize(vp, oldsize, TRUE); out: MPASS(IMPLIES(error == 0, uio->uio_resid == 0)); MPASS(IMPLIES(error != 0, oldsize == node->tn_size)); vn_rlimit_fsizex_res(uio, r); return (error); } static int tmpfs_deallocate(struct vop_deallocate_args *v) { return (tmpfs_reg_punch_hole(v->a_vp, v->a_offset, v->a_len)); } static int tmpfs_fsync(struct vop_fsync_args *v) { struct vnode *vp = v->a_vp; tmpfs_check_mtime(vp); tmpfs_update(vp); return (0); } static int tmpfs_remove(struct vop_remove_args *v) { struct vnode *dvp = v->a_dvp; struct vnode *vp = v->a_vp; int error; struct tmpfs_dirent *de; struct tmpfs_mount *tmp; struct tmpfs_node *dnode; struct tmpfs_node *node; if (vp->v_type == VDIR) { error = EISDIR; goto out; } dnode = VP_TO_TMPFS_DIR(dvp); node = VP_TO_TMPFS_NODE(vp); tmp = VFS_TO_TMPFS(vp->v_mount); de = tmpfs_dir_lookup(dnode, node, v->a_cnp); MPASS(de != NULL); /* Files marked as immutable or append-only cannot be deleted. */ if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) || (dnode->tn_flags & APPEND)) { error = EPERM; goto out; } /* Remove the entry from the directory; as it is a file, we do not * have to change the number of hard links of the directory. */ tmpfs_dir_detach(dvp, de); if (v->a_cnp->cn_flags & DOWHITEOUT) tmpfs_dir_whiteout_add(dvp, v->a_cnp); /* Free the directory entry we just deleted. Note that the node * referred by it will not be removed until the vnode is really * reclaimed. */ tmpfs_free_dirent(tmp, de); node->tn_status |= TMPFS_NODE_CHANGED; node->tn_accessed = true; error = 0; out: return (error); } static int tmpfs_link(struct vop_link_args *v) { struct vnode *dvp = v->a_tdvp; struct vnode *vp = v->a_vp; struct componentname *cnp = v->a_cnp; int error; struct tmpfs_dirent *de; struct tmpfs_node *node; MPASS(dvp != vp); /* XXX When can this be false? */ node = VP_TO_TMPFS_NODE(vp); /* Ensure that we do not overflow the maximum number of links imposed * by the system. */ MPASS(node->tn_links <= TMPFS_LINK_MAX); if (node->tn_links == TMPFS_LINK_MAX) { error = EMLINK; goto out; } /* We cannot create links of files marked immutable or append-only. */ if (node->tn_flags & (IMMUTABLE | APPEND)) { error = EPERM; goto out; } /* Allocate a new directory entry to represent the node. */ error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node, cnp->cn_nameptr, cnp->cn_namelen, &de); if (error != 0) goto out; /* Insert the new directory entry into the appropriate directory. */ if (cnp->cn_flags & ISWHITEOUT) tmpfs_dir_whiteout_remove(dvp, cnp); tmpfs_dir_attach(dvp, de); /* vp link count has changed, so update node times. */ node->tn_status |= TMPFS_NODE_CHANGED; tmpfs_update(vp); error = 0; out: return (error); } /* * We acquire all but fdvp locks using non-blocking acquisitions. If we * fail to acquire any lock in the path we will drop all held locks, * acquire the new lock in a blocking fashion, and then release it and * restart the rename. This acquire/release step ensures that we do not * spin on a lock waiting for release. On error release all vnode locks * and decrement references the way tmpfs_rename() would do. */ static int tmpfs_rename_relock(struct vnode *fdvp, struct vnode **fvpp, struct vnode *tdvp, struct vnode **tvpp, struct componentname *fcnp, struct componentname *tcnp) { struct vnode *nvp; struct mount *mp; struct tmpfs_dirent *de; int error, restarts = 0; VOP_UNLOCK(tdvp); if (*tvpp != NULL && *tvpp != tdvp) VOP_UNLOCK(*tvpp); mp = fdvp->v_mount; relock: restarts += 1; error = vn_lock(fdvp, LK_EXCLUSIVE); if (error) goto releout; if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) { VOP_UNLOCK(fdvp); error = vn_lock(tdvp, LK_EXCLUSIVE); if (error) goto releout; VOP_UNLOCK(tdvp); goto relock; } /* * Re-resolve fvp to be certain it still exists and fetch the * correct vnode. */ de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(fdvp), NULL, fcnp); if (de == NULL) { VOP_UNLOCK(fdvp); VOP_UNLOCK(tdvp); if ((fcnp->cn_flags & ISDOTDOT) != 0 || (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')) error = EINVAL; else error = ENOENT; goto releout; } error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE | LK_NOWAIT, &nvp); if (error != 0) { VOP_UNLOCK(fdvp); VOP_UNLOCK(tdvp); if (error != EBUSY) goto releout; error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE, &nvp); if (error != 0) goto releout; VOP_UNLOCK(nvp); /* * Concurrent rename race. */ if (nvp == tdvp) { vrele(nvp); error = EINVAL; goto releout; } vrele(*fvpp); *fvpp = nvp; goto relock; } vrele(*fvpp); *fvpp = nvp; VOP_UNLOCK(*fvpp); /* * Re-resolve tvp and acquire the vnode lock if present. */ de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(tdvp), NULL, tcnp); /* * If tvp disappeared we just carry on. */ if (de == NULL && *tvpp != NULL) { vrele(*tvpp); *tvpp = NULL; } /* * Get the tvp ino if the lookup succeeded. We may have to restart * if the non-blocking acquire fails. */ if (de != NULL) { nvp = NULL; error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE | LK_NOWAIT, &nvp); if (*tvpp != NULL) vrele(*tvpp); *tvpp = nvp; if (error != 0) { VOP_UNLOCK(fdvp); VOP_UNLOCK(tdvp); if (error != EBUSY) goto releout; error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE, &nvp); if (error != 0) goto releout; VOP_UNLOCK(nvp); /* * fdvp contains fvp, thus tvp (=fdvp) is not empty. */ if (nvp == fdvp) { error = ENOTEMPTY; goto releout; } goto relock; } } tmpfs_rename_restarts += restarts; return (0); releout: vrele(fdvp); vrele(*fvpp); vrele(tdvp); if (*tvpp != NULL) vrele(*tvpp); tmpfs_rename_restarts += restarts; return (error); } static int tmpfs_rename(struct vop_rename_args *v) { struct vnode *fdvp = v->a_fdvp; struct vnode *fvp = v->a_fvp; struct componentname *fcnp = v->a_fcnp; struct vnode *tdvp = v->a_tdvp; struct vnode *tvp = v->a_tvp; struct componentname *tcnp = v->a_tcnp; char *newname; struct tmpfs_dirent *de; struct tmpfs_mount *tmp; struct tmpfs_node *fdnode; struct tmpfs_node *fnode; struct tmpfs_node *tnode; struct tmpfs_node *tdnode; int error; bool want_seqc_end; want_seqc_end = false; /* * Disallow cross-device renames. * XXX Why isn't this done by the caller? */ if (fvp->v_mount != tdvp->v_mount || (tvp != NULL && fvp->v_mount != tvp->v_mount)) { error = EXDEV; goto out; } /* If source and target are the same file, there is nothing to do. */ if (fvp == tvp) { error = 0; goto out; } /* * If we need to move the directory between entries, lock the * source so that we can safely operate on it. */ if (fdvp != tdvp && fdvp != tvp) { if (vn_lock(fdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) { error = tmpfs_rename_relock(fdvp, &fvp, tdvp, &tvp, fcnp, tcnp); if (error != 0) return (error); ASSERT_VOP_ELOCKED(fdvp, "tmpfs_rename: fdvp not locked"); ASSERT_VOP_ELOCKED(tdvp, "tmpfs_rename: tdvp not locked"); if (tvp != NULL) ASSERT_VOP_ELOCKED(tvp, "tmpfs_rename: tvp not locked"); if (fvp == tvp) { error = 0; goto out_locked; } } } /* * Avoid manipulating '.' and '..' entries. */ if ((fcnp->cn_flags & ISDOTDOT) != 0 || (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')) { error = EINVAL; goto out_locked; } if (tvp != NULL) vn_seqc_write_begin(tvp); vn_seqc_write_begin(tdvp); vn_seqc_write_begin(fvp); vn_seqc_write_begin(fdvp); want_seqc_end = true; tmp = VFS_TO_TMPFS(tdvp->v_mount); tdnode = VP_TO_TMPFS_DIR(tdvp); tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp); fdnode = VP_TO_TMPFS_DIR(fdvp); fnode = VP_TO_TMPFS_NODE(fvp); de = tmpfs_dir_lookup(fdnode, fnode, fcnp); /* * Entry can disappear before we lock fdvp. */ if (de == NULL) { if ((fcnp->cn_flags & ISDOTDOT) != 0 || (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')) error = EINVAL; else error = ENOENT; goto out_locked; } MPASS(de->td_node == fnode); /* * If re-naming a directory to another preexisting directory * ensure that the target directory is empty so that its * removal causes no side effects. * Kern_rename guarantees the destination to be a directory * if the source is one. */ if (tvp != NULL) { MPASS(tnode != NULL); if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) || (tdnode->tn_flags & (APPEND | IMMUTABLE))) { error = EPERM; goto out_locked; } if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) { if (tnode->tn_size != 0 && ((tcnp->cn_flags & IGNOREWHITEOUT) == 0 || tnode->tn_size > tnode->tn_dir.tn_wht_size)) { error = ENOTEMPTY; goto out_locked; } } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) { error = ENOTDIR; goto out_locked; } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) { error = EISDIR; goto out_locked; } else { MPASS(fnode->tn_type != VDIR && tnode->tn_type != VDIR); } } if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) || (fdnode->tn_flags & (APPEND | IMMUTABLE))) { error = EPERM; goto out_locked; } /* * Ensure that we have enough memory to hold the new name, if it * has to be changed. */ if (fcnp->cn_namelen != tcnp->cn_namelen || bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) { newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK); } else newname = NULL; /* * If the node is being moved to another directory, we have to do * the move. */ if (fdnode != tdnode) { /* * In case we are moving a directory, we have to adjust its * parent to point to the new parent. */ if (de->td_node->tn_type == VDIR) { struct tmpfs_node *n; TMPFS_NODE_LOCK(fnode); error = tmpfs_access_locked(fvp, fnode, VWRITE, tcnp->cn_cred); TMPFS_NODE_UNLOCK(fnode); if (error) { if (newname != NULL) free(newname, M_TMPFSNAME); goto out_locked; } /* * Ensure the target directory is not a child of the * directory being moved. Otherwise, we'd end up * with stale nodes. */ n = tdnode; /* * TMPFS_LOCK guaranties that no nodes are freed while * traversing the list. Nodes can only be marked as * removed: tn_parent == NULL. */ TMPFS_LOCK(tmp); TMPFS_NODE_LOCK(n); while (n != n->tn_dir.tn_parent) { struct tmpfs_node *parent; if (n == fnode) { TMPFS_NODE_UNLOCK(n); TMPFS_UNLOCK(tmp); error = EINVAL; if (newname != NULL) free(newname, M_TMPFSNAME); goto out_locked; } parent = n->tn_dir.tn_parent; TMPFS_NODE_UNLOCK(n); if (parent == NULL) { n = NULL; break; } TMPFS_NODE_LOCK(parent); if (parent->tn_dir.tn_parent == NULL) { TMPFS_NODE_UNLOCK(parent); n = NULL; break; } n = parent; } TMPFS_UNLOCK(tmp); if (n == NULL) { error = EINVAL; if (newname != NULL) free(newname, M_TMPFSNAME); goto out_locked; } TMPFS_NODE_UNLOCK(n); /* Adjust the parent pointer. */ TMPFS_VALIDATE_DIR(fnode); TMPFS_NODE_LOCK(de->td_node); de->td_node->tn_dir.tn_parent = tdnode; TMPFS_NODE_UNLOCK(de->td_node); /* * As a result of changing the target of the '..' * entry, the link count of the source and target * directories has to be adjusted. */ TMPFS_NODE_LOCK(tdnode); TMPFS_ASSERT_LOCKED(tdnode); tdnode->tn_links++; TMPFS_NODE_UNLOCK(tdnode); TMPFS_NODE_LOCK(fdnode); TMPFS_ASSERT_LOCKED(fdnode); fdnode->tn_links--; TMPFS_NODE_UNLOCK(fdnode); } } /* * Do the move: just remove the entry from the source directory * and insert it into the target one. */ tmpfs_dir_detach(fdvp, de); if (fcnp->cn_flags & DOWHITEOUT) tmpfs_dir_whiteout_add(fdvp, fcnp); if (tcnp->cn_flags & ISWHITEOUT) tmpfs_dir_whiteout_remove(tdvp, tcnp); /* * If the name has changed, we need to make it effective by changing * it in the directory entry. */ if (newname != NULL) { MPASS(tcnp->cn_namelen <= MAXNAMLEN); free(de->ud.td_name, M_TMPFSNAME); de->ud.td_name = newname; tmpfs_dirent_init(de, tcnp->cn_nameptr, tcnp->cn_namelen); fnode->tn_status |= TMPFS_NODE_CHANGED; tdnode->tn_status |= TMPFS_NODE_MODIFIED; } /* * If we are overwriting an entry, we have to remove the old one * from the target directory. */ if (tvp != NULL) { struct tmpfs_dirent *tde; /* Remove the old entry from the target directory. */ tde = tmpfs_dir_lookup(tdnode, tnode, tcnp); tmpfs_dir_detach(tdvp, tde); /* * If we are overwriting a directory, per the ENOTEMPTY check * above it must either be empty or contain only whiteout * entries. In the latter case (which can only happen if * IGNOREWHITEOUT was passed in tcnp->cn_flags), clear the * whiteout entries to avoid leaking memory. */ if (tnode->tn_type == VDIR && tnode->tn_size > 0) tmpfs_dir_clear_whiteouts(tvp); /* Update node's ctime because of possible hardlinks. */ tnode->tn_status |= TMPFS_NODE_CHANGED; tmpfs_update(tvp); /* * Free the directory entry we just deleted. Note that the * node referred by it will not be removed until the vnode is * really reclaimed. */ tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), tde); } tmpfs_dir_attach(tdvp, de); if (tmpfs_use_nc(fvp)) { cache_vop_rename(fdvp, fvp, tdvp, tvp, fcnp, tcnp); } error = 0; out_locked: if (fdvp != tdvp && fdvp != tvp) VOP_UNLOCK(fdvp); out: if (want_seqc_end) { if (tvp != NULL) vn_seqc_write_end(tvp); vn_seqc_write_end(tdvp); vn_seqc_write_end(fvp); vn_seqc_write_end(fdvp); } /* * Release target nodes. * XXX: I don't understand when tdvp can be the same as tvp, but * other code takes care of this... */ if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp != NULL) vput(tvp); /* Release source nodes. */ vrele(fdvp); vrele(fvp); return (error); } static int tmpfs_mkdir(struct vop_mkdir_args *v) { struct vnode *dvp = v->a_dvp; struct vnode **vpp = v->a_vpp; struct componentname *cnp = v->a_cnp; struct vattr *vap = v->a_vap; MPASS(vap->va_type == VDIR); return (tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL)); } static int tmpfs_rmdir(struct vop_rmdir_args *v) { struct vnode *dvp = v->a_dvp; struct vnode *vp = v->a_vp; struct componentname *cnp = v->a_cnp; int error; struct tmpfs_dirent *de; struct tmpfs_mount *tmp; struct tmpfs_node *dnode; struct tmpfs_node *node; tmp = VFS_TO_TMPFS(dvp->v_mount); dnode = VP_TO_TMPFS_DIR(dvp); node = VP_TO_TMPFS_DIR(vp); /* * Directories with more than two non-whiteout entries ('.' and '..') * cannot be removed. */ if (node->tn_size != 0 && ((cnp->cn_flags & IGNOREWHITEOUT) == 0 || node->tn_size > node->tn_dir.tn_wht_size)) { error = ENOTEMPTY; goto out; } /* Check flags to see if we are allowed to remove the directory. */ if ((dnode->tn_flags & APPEND) || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) { error = EPERM; goto out; } /* This invariant holds only if we are not trying to remove "..". * We checked for that above so this is safe now. */ MPASS(node->tn_dir.tn_parent == dnode); /* Get the directory entry associated with node (vp). This was * filled by tmpfs_lookup while looking up the entry. */ de = tmpfs_dir_lookup(dnode, node, cnp); MPASS(TMPFS_DIRENT_MATCHES(de, cnp->cn_nameptr, cnp->cn_namelen)); /* Detach the directory entry from the directory (dnode). */ tmpfs_dir_detach(dvp, de); /* * If we are removing a directory, per the ENOTEMPTY check above it * must either be empty or contain only whiteout entries. In the * latter case (which can only happen if IGNOREWHITEOUT was passed * in cnp->cn_flags), clear the whiteout entries to avoid leaking * memory. */ if (node->tn_size > 0) tmpfs_dir_clear_whiteouts(vp); if (cnp->cn_flags & DOWHITEOUT) tmpfs_dir_whiteout_add(dvp, cnp); /* No vnode should be allocated for this entry from this point */ TMPFS_NODE_LOCK(node); node->tn_links--; node->tn_dir.tn_parent = NULL; node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; node->tn_accessed = true; TMPFS_NODE_UNLOCK(node); TMPFS_NODE_LOCK(dnode); dnode->tn_links--; dnode->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; dnode->tn_accessed = true; TMPFS_NODE_UNLOCK(dnode); if (tmpfs_use_nc(dvp)) { cache_vop_rmdir(dvp, vp); } /* Free the directory entry we just deleted. Note that the node * referred by it will not be removed until the vnode is really * reclaimed. */ tmpfs_free_dirent(tmp, de); /* Release the deleted vnode (will destroy the node, notify * interested parties and clean it from the cache). */ dnode->tn_status |= TMPFS_NODE_CHANGED; tmpfs_update(dvp); error = 0; out: return (error); } static int tmpfs_symlink(struct vop_symlink_args *v) { struct vnode *dvp = v->a_dvp; struct vnode **vpp = v->a_vpp; struct componentname *cnp = v->a_cnp; struct vattr *vap = v->a_vap; const char *target = v->a_target; #ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */ MPASS(vap->va_type == VLNK); #else vap->va_type = VLNK; #endif return (tmpfs_alloc_file(dvp, vpp, vap, cnp, target)); } static int tmpfs_readdir(struct vop_readdir_args *va) { struct vnode *vp; struct uio *uio; struct tmpfs_mount *tm; struct tmpfs_node *node; uint64_t **cookies; int *eofflag, *ncookies; ssize_t startresid; int error, maxcookies; vp = va->a_vp; uio = va->a_uio; eofflag = va->a_eofflag; cookies = va->a_cookies; ncookies = va->a_ncookies; /* This operation only makes sense on directory nodes. */ if (vp->v_type != VDIR) return (ENOTDIR); maxcookies = 0; node = VP_TO_TMPFS_DIR(vp); tm = VFS_TO_TMPFS(vp->v_mount); startresid = uio->uio_resid; /* Allocate cookies for NFS and compat modules. */ if (cookies != NULL && ncookies != NULL) { maxcookies = howmany(node->tn_size, sizeof(struct tmpfs_dirent)) + 2; *cookies = malloc(maxcookies * sizeof(**cookies), M_TEMP, M_WAITOK); *ncookies = 0; } if (cookies == NULL) error = tmpfs_dir_getdents(tm, node, uio, 0, NULL, NULL); else error = tmpfs_dir_getdents(tm, node, uio, maxcookies, *cookies, ncookies); /* Buffer was filled without hitting EOF. */ if (error == EJUSTRETURN) error = (uio->uio_resid != startresid) ? 0 : EINVAL; if (error != 0 && cookies != NULL && ncookies != NULL) { free(*cookies, M_TEMP); *cookies = NULL; *ncookies = 0; } if (eofflag != NULL) *eofflag = (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF); return (error); } static int tmpfs_readlink(struct vop_readlink_args *v) { struct vnode *vp = v->a_vp; struct uio *uio = v->a_uio; int error; struct tmpfs_node *node; MPASS(uio->uio_offset == 0); MPASS(vp->v_type == VLNK); node = VP_TO_TMPFS_NODE(vp); error = uiomove(node->tn_link_target, MIN(node->tn_size, uio->uio_resid), uio); tmpfs_set_accessed(VFS_TO_TMPFS(vp->v_mount), node); return (error); } /* * VOP_FPLOOKUP_SYMLINK routines are subject to special circumstances, see * the comment above cache_fplookup for details. * * Check tmpfs_alloc_node for tmpfs-specific synchronisation notes. */ static int tmpfs_fplookup_symlink(struct vop_fplookup_symlink_args *v) { struct vnode *vp; struct tmpfs_node *node; char *symlink; vp = v->a_vp; node = VP_TO_TMPFS_NODE_SMR(vp); if (__predict_false(node == NULL)) return (EAGAIN); if (!atomic_load_char(&node->tn_link_smr)) return (EAGAIN); symlink = atomic_load_ptr(&node->tn_link_target); if (symlink == NULL) return (EAGAIN); return (cache_symlink_resolve(v->a_fpl, symlink, node->tn_size)); } static int tmpfs_inactive(struct vop_inactive_args *v) { struct vnode *vp; struct tmpfs_node *node; vp = v->a_vp; node = VP_TO_TMPFS_NODE(vp); if (node->tn_links == 0) vrecycle(vp); else tmpfs_check_mtime(vp); return (0); } static int tmpfs_need_inactive(struct vop_need_inactive_args *ap) { struct vnode *vp; struct tmpfs_node *node; struct vm_object *obj; vp = ap->a_vp; node = VP_TO_TMPFS_NODE(vp); if (node->tn_links == 0) goto need; if (vp->v_type == VREG) { obj = vp->v_object; if (obj->generation != obj->cleangeneration) goto need; } return (0); need: return (1); } int tmpfs_reclaim(struct vop_reclaim_args *v) { struct vnode *vp; struct tmpfs_mount *tmp; struct tmpfs_node *node; bool unlock; vp = v->a_vp; node = VP_TO_TMPFS_NODE(vp); tmp = VFS_TO_TMPFS(vp->v_mount); if (vp->v_type == VREG) tmpfs_destroy_vobject(vp, node->tn_reg.tn_aobj); vp->v_object = NULL; TMPFS_LOCK(tmp); TMPFS_NODE_LOCK(node); tmpfs_free_vp(vp); /* * If the node referenced by this vnode was deleted by the user, * we must free its associated data structures (now that the vnode * is being reclaimed). */ unlock = true; if (node->tn_links == 0 && (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0) { node->tn_vpstate = TMPFS_VNODE_DOOMED; unlock = !tmpfs_free_node_locked(tmp, node, true); } if (unlock) { TMPFS_NODE_UNLOCK(node); TMPFS_UNLOCK(tmp); } MPASS(vp->v_data == NULL); return (0); } int tmpfs_print(struct vop_print_args *v) { struct vnode *vp = v->a_vp; struct tmpfs_node *node; node = VP_TO_TMPFS_NODE(vp); printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%lx, links %jd\n", node, node->tn_flags, (uintmax_t)node->tn_links); printf("\tmode 0%o, owner %d, group %d, size %jd, status 0x%x\n", node->tn_mode, node->tn_uid, node->tn_gid, (intmax_t)node->tn_size, node->tn_status); if (vp->v_type == VFIFO) fifo_printinfo(vp); printf("\n"); return (0); } int tmpfs_pathconf(struct vop_pathconf_args *v) { struct vnode *vp = v->a_vp; int name = v->a_name; long *retval = v->a_retval; int error; error = 0; switch (name) { case _PC_LINK_MAX: *retval = TMPFS_LINK_MAX; break; case _PC_SYMLINK_MAX: *retval = MAXPATHLEN; break; case _PC_NAME_MAX: *retval = NAME_MAX; break; case _PC_PIPE_BUF: if (vp->v_type == VDIR || vp->v_type == VFIFO) *retval = PIPE_BUF; else error = EINVAL; break; case _PC_CHOWN_RESTRICTED: *retval = 1; break; case _PC_NO_TRUNC: *retval = 1; break; case _PC_SYNC_IO: *retval = 1; break; case _PC_FILESIZEBITS: *retval = 64; break; case _PC_MIN_HOLE_SIZE: *retval = PAGE_SIZE; break; case _PC_HAS_HIDDENSYSTEM: *retval = 1; break; default: error = vop_stdpathconf(v); } return (error); } static int tmpfs_vptofh(struct vop_vptofh_args *ap) /* vop_vptofh { IN struct vnode *a_vp; IN struct fid *a_fhp; }; */ { struct tmpfs_fid_data *const tfd = (struct tmpfs_fid_data *)ap->a_fhp; struct tmpfs_node *node; _Static_assert(sizeof(struct tmpfs_fid_data) <= sizeof(struct fid), "struct tmpfs_fid_data cannot be larger than struct fid"); node = VP_TO_TMPFS_NODE(ap->a_vp); tfd->tfd_len = sizeof(*tfd); tfd->tfd_gen = node->tn_gen; tfd->tfd_id = node->tn_id; return (0); } static int tmpfs_whiteout(struct vop_whiteout_args *ap) { struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; struct tmpfs_dirent *de; switch (ap->a_flags) { case LOOKUP: return (0); case CREATE: de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp); if (de != NULL) return (de->td_node == NULL ? 0 : EEXIST); return (tmpfs_dir_whiteout_add(dvp, cnp)); case DELETE: tmpfs_dir_whiteout_remove(dvp, cnp); return (0); default: panic("tmpfs_whiteout: unknown op"); } } static int tmpfs_vptocnp_dir(struct tmpfs_node *tn, struct tmpfs_node *tnp, struct tmpfs_dirent **pde) { struct tmpfs_dir_cursor dc; struct tmpfs_dirent *de; for (de = tmpfs_dir_first(tnp, &dc); de != NULL; de = tmpfs_dir_next(tnp, &dc)) { if (de->td_node == tn) { *pde = de; return (0); } } return (ENOENT); } static int tmpfs_vptocnp_fill(struct vnode *vp, struct tmpfs_node *tn, struct tmpfs_node *tnp, char *buf, size_t *buflen, struct vnode **dvp) { struct tmpfs_dirent *de; int error, i; error = vn_vget_ino_gen(vp, tmpfs_vn_get_ino_alloc, tnp, LK_SHARED, dvp); if (error != 0) return (error); error = tmpfs_vptocnp_dir(tn, tnp, &de); if (error == 0) { i = *buflen; i -= de->td_namelen; if (i < 0) { error = ENOMEM; } else { bcopy(de->ud.td_name, buf + i, de->td_namelen); *buflen = i; } } if (error == 0) { if (vp != *dvp) VOP_UNLOCK(*dvp); } else { if (vp != *dvp) vput(*dvp); else vrele(vp); } return (error); } static int tmpfs_vptocnp(struct vop_vptocnp_args *ap) { struct vnode *vp, **dvp; struct tmpfs_node *tn, *tnp, *tnp1; struct tmpfs_dirent *de; struct tmpfs_mount *tm; char *buf; size_t *buflen; int error; vp = ap->a_vp; dvp = ap->a_vpp; buf = ap->a_buf; buflen = ap->a_buflen; tm = VFS_TO_TMPFS(vp->v_mount); tn = VP_TO_TMPFS_NODE(vp); if (tn->tn_type == VDIR) { tnp = tn->tn_dir.tn_parent; if (tnp == NULL) return (ENOENT); tmpfs_ref_node(tnp); error = tmpfs_vptocnp_fill(vp, tn, tn->tn_dir.tn_parent, buf, buflen, dvp); tmpfs_free_node(tm, tnp); return (error); } restart: TMPFS_LOCK(tm); restart_locked: LIST_FOREACH_SAFE(tnp, &tm->tm_nodes_used, tn_entries, tnp1) { if (tnp->tn_type != VDIR) continue; TMPFS_NODE_LOCK(tnp); tmpfs_ref_node(tnp); /* * tn_vnode cannot be instantiated while we hold the * node lock, so the directory cannot be changed while * we iterate over it. Do this to avoid instantiating * vnode for directories which cannot point to our * node. */ error = tnp->tn_vnode == NULL ? tmpfs_vptocnp_dir(tn, tnp, &de) : 0; if (error == 0) { TMPFS_NODE_UNLOCK(tnp); TMPFS_UNLOCK(tm); error = tmpfs_vptocnp_fill(vp, tn, tnp, buf, buflen, dvp); if (error == 0) { tmpfs_free_node(tm, tnp); return (0); } if (VN_IS_DOOMED(vp)) { tmpfs_free_node(tm, tnp); return (ENOENT); } TMPFS_LOCK(tm); TMPFS_NODE_LOCK(tnp); } if (tmpfs_free_node_locked(tm, tnp, false)) { goto restart; } else { KASSERT(tnp->tn_refcount > 0, ("node %p refcount zero", tnp)); if (tnp->tn_attached) { tnp1 = LIST_NEXT(tnp, tn_entries); TMPFS_NODE_UNLOCK(tnp); } else { TMPFS_NODE_UNLOCK(tnp); goto restart_locked; } } } TMPFS_UNLOCK(tm); return (ENOENT); } void tmpfs_extattr_free(struct tmpfs_extattr *ea) { free(ea->ea_name, M_TMPFSEA); free(ea->ea_value, M_TMPFSEA); free(ea, M_TMPFSEA); } static bool tmpfs_extattr_update_mem(struct tmpfs_mount *tmp, ssize_t size) { TMPFS_LOCK(tmp); if (size > 0 && !tmpfs_pages_check_avail(tmp, howmany(size, PAGE_SIZE))) { TMPFS_UNLOCK(tmp); return (false); } if (tmp->tm_ea_memory_inuse + size > tmp->tm_ea_memory_max) { TMPFS_UNLOCK(tmp); return (false); } tmp->tm_ea_memory_inuse += size; TMPFS_UNLOCK(tmp); return (true); } static int tmpfs_deleteextattr(struct vop_deleteextattr_args *ap) { struct vnode *vp = ap->a_vp; struct tmpfs_mount *tmp; struct tmpfs_node *node; struct tmpfs_extattr *ea; size_t namelen; ssize_t diff; int error; node = VP_TO_TMPFS_NODE(vp); tmp = VFS_TO_TMPFS(vp->v_mount); 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); if (error != 0) return (error); if (ap->a_name == NULL || ap->a_name[0] == '\0') return (EINVAL); namelen = strlen(ap->a_name); if (namelen > EXTATTR_MAXNAMELEN) return (EINVAL); LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) { if (ea->ea_namespace == ap->a_attrnamespace && namelen == ea->ea_namelen && memcmp(ap->a_name, ea->ea_name, namelen) == 0) break; } if (ea == NULL) return (ENOATTR); LIST_REMOVE(ea, ea_extattrs); diff = -(sizeof(struct tmpfs_extattr) + namelen + ea->ea_size); tmpfs_extattr_update_mem(tmp, diff); tmpfs_extattr_free(ea); return (0); } static int tmpfs_getextattr(struct vop_getextattr_args *ap) { struct vnode *vp = ap->a_vp; struct tmpfs_node *node; struct tmpfs_extattr *ea; size_t namelen; int error; node = VP_TO_TMPFS_NODE(vp); 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); if (error != 0) return (error); if (ap->a_name == NULL || ap->a_name[0] == '\0') return (EINVAL); namelen = strlen(ap->a_name); if (namelen > EXTATTR_MAXNAMELEN) return (EINVAL); LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) { if (ea->ea_namespace == ap->a_attrnamespace && namelen == ea->ea_namelen && memcmp(ap->a_name, ea->ea_name, namelen) == 0) break; } if (ea == NULL) return (ENOATTR); if (ap->a_size != NULL) *ap->a_size = ea->ea_size; if (ap->a_uio != NULL && ea->ea_size != 0) error = uiomove(ea->ea_value, ea->ea_size, ap->a_uio); return (error); } static int tmpfs_listextattr(struct vop_listextattr_args *ap) { struct vnode *vp = ap->a_vp; struct tmpfs_node *node; struct tmpfs_extattr *ea; int error; node = VP_TO_TMPFS_NODE(vp); 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); if (error != 0) return (error); if (ap->a_size != NULL) *ap->a_size = 0; LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) { if (ea->ea_namespace != ap->a_attrnamespace) continue; if (ap->a_size != NULL) *ap->a_size += ea->ea_namelen + 1; if (ap->a_uio != NULL) { error = uiomove(&ea->ea_namelen, 1, ap->a_uio); if (error != 0) break; error = uiomove(ea->ea_name, ea->ea_namelen, ap->a_uio); if (error != 0) break; } } return (error); } static int tmpfs_setextattr(struct vop_setextattr_args *ap) { struct vnode *vp = ap->a_vp; struct tmpfs_mount *tmp; struct tmpfs_node *node; struct tmpfs_extattr *ea; struct tmpfs_extattr *new_ea; size_t attr_size; size_t namelen; ssize_t diff; int error; node = VP_TO_TMPFS_NODE(vp); tmp = VFS_TO_TMPFS(vp->v_mount); attr_size = ap->a_uio->uio_resid; diff = 0; 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); if (error != 0) return (error); if (ap->a_name == NULL || ap->a_name[0] == '\0') return (EINVAL); namelen = strlen(ap->a_name); if (namelen > EXTATTR_MAXNAMELEN) return (EINVAL); LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) { if (ea->ea_namespace == ap->a_attrnamespace && namelen == ea->ea_namelen && memcmp(ap->a_name, ea->ea_name, namelen) == 0) { diff -= sizeof(struct tmpfs_extattr) + ea->ea_namelen + ea->ea_size; break; } } diff += sizeof(struct tmpfs_extattr) + namelen + attr_size; if (!tmpfs_extattr_update_mem(tmp, diff)) return (ENOSPC); new_ea = malloc(sizeof(struct tmpfs_extattr), M_TMPFSEA, M_WAITOK); new_ea->ea_namespace = ap->a_attrnamespace; new_ea->ea_name = malloc(namelen, M_TMPFSEA, M_WAITOK); new_ea->ea_namelen = namelen; memcpy(new_ea->ea_name, ap->a_name, namelen); if (attr_size != 0) { new_ea->ea_value = malloc(attr_size, M_TMPFSEA, M_WAITOK); new_ea->ea_size = attr_size; error = uiomove(new_ea->ea_value, attr_size, ap->a_uio); } else { new_ea->ea_value = NULL; new_ea->ea_size = 0; } if (error != 0) { tmpfs_extattr_update_mem(tmp, -diff); tmpfs_extattr_free(new_ea); return (error); } if (ea != NULL) { LIST_REMOVE(ea, ea_extattrs); tmpfs_extattr_free(ea); } LIST_INSERT_HEAD(&node->tn_extattrs, new_ea, ea_extattrs); return (0); } static off_t tmpfs_seek_data_locked(vm_object_t obj, off_t noff) { vm_pindex_t p; p = swap_pager_seek_data(obj, OFF_TO_IDX(noff)); return (p == OFF_TO_IDX(noff) ? noff : IDX_TO_OFF(p)); } static int tmpfs_seek_clamp(struct tmpfs_node *tn, off_t *noff, bool seekdata) { if (*noff < tn->tn_size) return (0); if (seekdata) return (ENXIO); *noff = tn->tn_size; return (0); } static off_t tmpfs_seek_hole_locked(vm_object_t obj, off_t noff) { return (IDX_TO_OFF(swap_pager_seek_hole(obj, OFF_TO_IDX(noff)))); } static int tmpfs_seek_datahole(struct vnode *vp, off_t *off, bool seekdata) { struct tmpfs_node *tn; vm_object_t obj; off_t noff; int error; if (vp->v_type != VREG) return (ENOTTY); tn = VP_TO_TMPFS_NODE(vp); noff = *off; if (noff < 0) return (ENXIO); error = tmpfs_seek_clamp(tn, &noff, seekdata); if (error != 0) return (error); obj = tn->tn_reg.tn_aobj; VM_OBJECT_RLOCK(obj); noff = seekdata ? tmpfs_seek_data_locked(obj, noff) : tmpfs_seek_hole_locked(obj, noff); VM_OBJECT_RUNLOCK(obj); error = tmpfs_seek_clamp(tn, &noff, seekdata); if (error == 0) *off = noff; return (error); } static int tmpfs_ioctl(struct vop_ioctl_args *ap) { struct vnode *vp = ap->a_vp; int error = 0; switch (ap->a_command) { case FIOSEEKDATA: case FIOSEEKHOLE: error = vn_lock(vp, LK_SHARED); if (error != 0) { error = EBADF; break; } error = tmpfs_seek_datahole(vp, (off_t *)ap->a_data, ap->a_command == FIOSEEKDATA); VOP_UNLOCK(vp); break; default: error = ENOTTY; break; } return (error); } /* * Vnode operations vector used for files stored in a tmpfs file system. */ struct vop_vector tmpfs_vnodeop_entries = { .vop_default = &default_vnodeops, .vop_lookup = vfs_cache_lookup, .vop_cachedlookup = tmpfs_cached_lookup, .vop_create = tmpfs_create, .vop_mknod = tmpfs_mknod, .vop_open = tmpfs_open, .vop_close = tmpfs_close, .vop_fplookup_vexec = tmpfs_fplookup_vexec, .vop_fplookup_symlink = tmpfs_fplookup_symlink, .vop_access = tmpfs_access, .vop_stat = tmpfs_stat, .vop_getattr = tmpfs_getattr, .vop_setattr = tmpfs_setattr, .vop_read = tmpfs_read, .vop_read_pgcache = tmpfs_read_pgcache, .vop_write = tmpfs_write, .vop_deallocate = tmpfs_deallocate, .vop_fsync = tmpfs_fsync, .vop_remove = tmpfs_remove, .vop_link = tmpfs_link, .vop_rename = tmpfs_rename, .vop_mkdir = tmpfs_mkdir, .vop_rmdir = tmpfs_rmdir, .vop_symlink = tmpfs_symlink, .vop_readdir = tmpfs_readdir, .vop_readlink = tmpfs_readlink, .vop_inactive = tmpfs_inactive, .vop_need_inactive = tmpfs_need_inactive, .vop_reclaim = tmpfs_reclaim, .vop_print = tmpfs_print, .vop_pathconf = tmpfs_pathconf, .vop_vptofh = tmpfs_vptofh, .vop_whiteout = tmpfs_whiteout, .vop_bmap = VOP_EOPNOTSUPP, .vop_vptocnp = tmpfs_vptocnp, .vop_lock1 = vop_lock, .vop_unlock = vop_unlock, .vop_islocked = vop_islocked, .vop_deleteextattr = tmpfs_deleteextattr, .vop_getextattr = tmpfs_getextattr, .vop_listextattr = tmpfs_listextattr, .vop_setextattr = tmpfs_setextattr, .vop_add_writecount = vop_stdadd_writecount_nomsync, .vop_ioctl = tmpfs_ioctl, }; VFS_VOP_VECTOR_REGISTER(tmpfs_vnodeop_entries); /* * Same vector for mounts which do not use namecache. */ struct vop_vector tmpfs_vnodeop_nonc_entries = { .vop_default = &tmpfs_vnodeop_entries, .vop_lookup = tmpfs_lookup, }; VFS_VOP_VECTOR_REGISTER(tmpfs_vnodeop_nonc_entries); diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c index 37889241e8c3..ec61618b6e18 100644 --- a/sys/fs/udf/udf_vnops.c +++ b/sys/fs/udf/udf_vnops.c @@ -1,1508 +1,1508 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2001, 2002 Scott Long * All rights reserved. * * 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. */ /* udf_vnops.c */ /* Take care of the vnode side of things */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern struct iconv_functions *udf_iconv; static vop_access_t udf_access; static vop_getattr_t udf_getattr; static vop_open_t udf_open; static vop_ioctl_t udf_ioctl; static vop_pathconf_t udf_pathconf; static vop_print_t udf_print; static vop_read_t udf_read; static vop_readdir_t udf_readdir; static vop_readlink_t udf_readlink; static vop_setattr_t udf_setattr; static vop_strategy_t udf_strategy; static vop_bmap_t udf_bmap; static vop_cachedlookup_t udf_lookup; static vop_reclaim_t udf_reclaim; static vop_vptofh_t udf_vptofh; static int udf_readatoffset(struct udf_node *node, int *size, off_t offset, struct buf **bp, uint8_t **data); static int udf_bmap_internal(struct udf_node *node, off_t offset, daddr_t *sector, uint32_t *max_size); static struct vop_vector udf_vnodeops = { .vop_default = &default_vnodeops, .vop_access = udf_access, .vop_bmap = udf_bmap, .vop_cachedlookup = udf_lookup, .vop_getattr = udf_getattr, .vop_ioctl = udf_ioctl, .vop_lookup = vfs_cache_lookup, .vop_open = udf_open, .vop_pathconf = udf_pathconf, .vop_print = udf_print, .vop_read = udf_read, .vop_readdir = udf_readdir, .vop_readlink = udf_readlink, .vop_reclaim = udf_reclaim, .vop_setattr = udf_setattr, .vop_strategy = udf_strategy, .vop_vptofh = udf_vptofh, }; VFS_VOP_VECTOR_REGISTER(udf_vnodeops); struct vop_vector udf_fifoops = { .vop_default = &fifo_specops, .vop_access = udf_access, .vop_getattr = udf_getattr, .vop_pathconf = udf_pathconf, .vop_print = udf_print, .vop_reclaim = udf_reclaim, .vop_setattr = udf_setattr, .vop_vptofh = udf_vptofh, }; VFS_VOP_VECTOR_REGISTER(udf_fifoops); static MALLOC_DEFINE(M_UDFFID, "udf_fid", "UDF FileId structure"); static MALLOC_DEFINE(M_UDFDS, "udf_ds", "UDF Dirstream structure"); #define UDF_INVALID_BMAP -1 int udf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td) { int error; struct vnode *vp; error = getnewvnode("udf", mp, &udf_vnodeops, &vp); if (error) { printf("udf_allocv: failed to allocate new vnode\n"); return (error); } *vpp = vp; return (0); } /* Convert file entry permission (5 bits per owner/group/user) to a mode_t */ static mode_t udf_permtomode(struct udf_node *node) { uint32_t perm; uint16_t flags; mode_t mode; perm = le32toh(node->fentry->perm); flags = le16toh(node->fentry->icbtag.flags); mode = perm & UDF_FENTRY_PERM_USER_MASK; mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2); mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4); mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4); mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6); mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8); return (mode); } static int udf_access(struct vop_access_args *a) { struct vnode *vp; struct udf_node *node; accmode_t accmode; mode_t mode; vp = a->a_vp; node = VTON(vp); accmode = a->a_accmode; if (accmode & VWRITE) { switch (vp->v_type) { case VDIR: case VLNK: case VREG: return (EROFS); /* NOT REACHED */ default: break; } } mode = udf_permtomode(node); return (vaccess(vp->v_type, mode, node->fentry->uid, node->fentry->gid, accmode, a->a_cred)); } static int udf_open(struct vop_open_args *ap) { struct udf_node *np = VTON(ap->a_vp); uint64_t fsize; fsize = le64toh(np->fentry->inf_len); if (fsize > OFF_MAX) return (EIO); vnode_create_vobject(ap->a_vp, fsize, ap->a_td); return 0; } static const int mon_lens[2][12] = { {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} }; static int udf_isaleapyear(int year) { int i; i = (year % 4) ? 0 : 1; i &= (year % 100) ? 1 : 0; i |= (year % 400) ? 0 : 1; return i; } /* * Timezone calculation compliments of Julian Elischer . */ static void udf_timetotimespec(struct timestamp *time, struct timespec *t) { int i, lpyear, daysinyear, year, startyear; union { uint16_t u_tz_offset; int16_t s_tz_offset; } tz; /* * DirectCD seems to like using bogus year values. * Don't trust time->month as it will be used for an array index. */ year = le16toh(time->year); if (year < 1970 || time->month < 1 || time->month > 12) { t->tv_sec = 0; t->tv_nsec = 0; return; } /* Calculate the time and day */ t->tv_sec = time->second; t->tv_sec += time->minute * 60; t->tv_sec += time->hour * 3600; t->tv_sec += (time->day - 1) * 3600 * 24; /* Calculate the month */ lpyear = udf_isaleapyear(year); t->tv_sec += mon_lens[lpyear][time->month - 1] * 3600 * 24; /* Speed up the calculation */ startyear = 1970; if (year > 2009) { t->tv_sec += 1262304000; startyear += 40; } else if (year > 1999) { t->tv_sec += 946684800; startyear += 30; } else if (year > 1989) { t->tv_sec += 631152000; startyear += 20; } else if (year > 1979) { t->tv_sec += 315532800; startyear += 10; } daysinyear = (year - startyear) * 365; for (i = startyear; i < year; i++) daysinyear += udf_isaleapyear(i); t->tv_sec += daysinyear * 3600 * 24; /* Calculate microseconds */ t->tv_nsec = time->centisec * 10000 + time->hund_usec * 100 + time->usec; /* * Calculate the time zone. The timezone is 12 bit signed 2's * complement, so we gotta do some extra magic to handle it right. */ tz.u_tz_offset = le16toh(time->type_tz); tz.u_tz_offset &= 0x0fff; if (tz.u_tz_offset & 0x0800) tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */ if ((le16toh(time->type_tz) & 0x1000) && (tz.s_tz_offset != -2047)) t->tv_sec -= tz.s_tz_offset * 60; return; } static int udf_getattr(struct vop_getattr_args *a) { struct vnode *vp; struct udf_node *node; struct vattr *vap; struct file_entry *fentry; vp = a->a_vp; vap = a->a_vap; node = VTON(vp); fentry = node->fentry; vap->va_fsid = dev2udev(node->udfmp->im_dev); vap->va_fileid = node->hash_id; vap->va_mode = udf_permtomode(node); vap->va_nlink = le16toh(fentry->link_cnt); /* * XXX The spec says that -1 is valid for uid/gid and indicates an * invalid uid/gid. How should this be represented? */ vap->va_uid = (le32toh(fentry->uid) == -1) ? 0 : le32toh(fentry->uid); vap->va_gid = (le32toh(fentry->gid) == -1) ? 0 : le32toh(fentry->gid); udf_timetotimespec(&fentry->atime, &vap->va_atime); udf_timetotimespec(&fentry->mtime, &vap->va_mtime); vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */ vap->va_rdev = NODEV; if (vp->v_type & VDIR) { /* * Directories that are recorded within their ICB will show * as having 0 blocks recorded. Since tradition dictates * that directories consume at least one logical block, * make it appear so. */ vap->va_size = le64toh(fentry->logblks_rec); if (vap->va_size == 0) vap->va_size = node->udfmp->bsize; else if (vap->va_size > UINT64_MAX / node->udfmp->bsize) vap->va_size = UINT64_MAX; else vap->va_size *= node->udfmp->bsize; } else { vap->va_size = le64toh(fentry->inf_len); } vap->va_flags = 0; vap->va_gen = 1; vap->va_blocksize = node->udfmp->bsize; vap->va_bytes = le64toh(fentry->inf_len); vap->va_type = vp->v_type; vap->va_filerev = 0; /* XXX */ return (0); } static int udf_setattr(struct vop_setattr_args *a) { struct vnode *vp; struct vattr *vap; vp = a->a_vp; vap = a->a_vap; if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) return (EROFS); if (vap->va_size != (u_quad_t)VNOVAL) { switch (vp->v_type) { case VDIR: return (EISDIR); case VLNK: case VREG: return (EROFS); case VCHR: case VBLK: case VSOCK: case VFIFO: case VNON: case VBAD: case VMARKER: return (0); } } return (0); } /* * File specific ioctls. */ static int udf_ioctl(struct vop_ioctl_args *a) { printf("%s called\n", __func__); return (ENOTTY); } /* * I'm not sure that this has much value in a read-only filesystem, but * cd9660 has it too. */ static int udf_pathconf(struct vop_pathconf_args *a) { switch (a->a_name) { case _PC_FILESIZEBITS: *a->a_retval = 64; return (0); case _PC_LINK_MAX: *a->a_retval = 65535; return (0); case _PC_NAME_MAX: *a->a_retval = NAME_MAX; return (0); case _PC_SYMLINK_MAX: *a->a_retval = MAXPATHLEN; return (0); case _PC_NO_TRUNC: *a->a_retval = 1; return (0); case _PC_PIPE_BUF: if (a->a_vp->v_type == VDIR || a->a_vp->v_type == VFIFO) { *a->a_retval = PIPE_BUF; return (0); } return (EINVAL); default: return (vop_stdpathconf(a)); } } static int udf_print(struct vop_print_args *ap) { struct vnode *vp = ap->a_vp; struct udf_node *node = VTON(vp); printf(" ino %lu, on dev %s", (u_long)node->hash_id, devtoname(node->udfmp->im_dev)); if (vp->v_type == VFIFO) fifo_printinfo(vp); printf("\n"); return (0); } #define lblkno(udfmp, loc) ((loc) >> (udfmp)->bshift) #define blkoff(udfmp, loc) ((loc) & (udfmp)->bmask) #define lblktosize(udfmp, blk) ((blk) << (udfmp)->bshift) static inline int is_data_in_fentry(const struct udf_node *node) { const struct file_entry *fentry = node->fentry; return ((le16toh(fentry->icbtag.flags) & 0x7) == 3); } static int udf_read(struct vop_read_args *ap) { struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct udf_node *node = VTON(vp); struct udf_mnt *udfmp; struct file_entry *fentry; struct buf *bp; uint8_t *data; daddr_t lbn, rablock; uint64_t len; off_t diff, fsize; ssize_t n; int error = 0; long size, on; if (uio->uio_resid == 0) return (0); if (uio->uio_offset < 0) return (EINVAL); if (is_data_in_fentry(node)) { fentry = node->fentry; data = &fentry->data[le32toh(fentry->l_ea)]; fsize = le32toh(fentry->l_ad); n = uio->uio_resid; diff = fsize - uio->uio_offset; if (diff <= 0) return (0); if (diff < n) n = diff; error = uiomove(data + uio->uio_offset, (int)n, uio); return (error); } len = le64toh(node->fentry->inf_len); if (len > OFF_MAX) { /* too big, just cap to the requested length */ len = uio->uio_resid; } fsize = len; udfmp = node->udfmp; do { lbn = lblkno(udfmp, uio->uio_offset); on = blkoff(udfmp, uio->uio_offset); n = min((u_int)(udfmp->bsize - on), uio->uio_resid); diff = fsize - uio->uio_offset; if (diff <= 0) return (0); if (diff < n) n = diff; size = udfmp->bsize; rablock = lbn + 1; if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { if (lblktosize(udfmp, rablock) < fsize) { error = cluster_read(vp, fsize, lbn, size, NOCRED, uio->uio_resid, (ap->a_ioflag >> 16), 0, &bp); } else { error = bread(vp, lbn, size, NOCRED, &bp); } } else { error = bread(vp, lbn, size, NOCRED, &bp); } if (error != 0) { brelse(bp); return (error); } n = min(n, size - bp->b_resid); error = uiomove(bp->b_data + on, (int)n, uio); brelse(bp); } while (error == 0 && uio->uio_resid > 0 && n != 0); return (error); } /* * Call the OSTA routines to translate the name from a CS0 dstring to a * 16-bit Unicode String. Hooks need to be placed in here to translate from * Unicode to the encoding that the kernel/user expects. Return the length * of the translated string. */ static int udf_transname(char *cs0string, char *destname, int len, struct udf_mnt *udfmp) { unicode_t *transname; char *unibuf, *unip; int i, destlen; ssize_t unilen = 0; size_t destleft = MAXNAMLEN; /* Convert 16-bit Unicode to destname */ if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) { /* allocate a buffer big enough to hold an 8->16 bit expansion */ unibuf = uma_zalloc(udf_zone_trans, M_WAITOK); unip = unibuf; if ((unilen = (ssize_t)udf_UncompressUnicodeByte(len, cs0string, unibuf)) == -1) { printf("udf: Unicode translation failed\n"); uma_zfree(udf_zone_trans, unibuf); return 0; } while (unilen > 0 && destleft > 0) { udf_iconv->conv(udfmp->im_d2l, __DECONST(const char **, &unibuf), (size_t *)&unilen, (char **)&destname, &destleft); /* Unconverted character found */ if (unilen > 0 && destleft > 0) { *destname++ = '?'; destleft--; unibuf += 2; unilen -= 2; } } uma_zfree(udf_zone_trans, unip); *destname = '\0'; destlen = MAXNAMLEN - (int)destleft; } else { /* allocate a buffer big enough to hold an 8->16 bit expansion */ transname = uma_zalloc(udf_zone_trans, M_WAITOK); if ((unilen = (ssize_t)udf_UncompressUnicode(len, cs0string, transname)) == -1) { printf("udf: Unicode translation failed\n"); uma_zfree(udf_zone_trans, transname); return 0; } for (i = 0; i < unilen ; i++) { if (transname[i] & 0xff00) { destname[i] = '.'; /* Fudge the 16bit chars */ } else { destname[i] = transname[i] & 0xff; } } uma_zfree(udf_zone_trans, transname); destname[unilen] = 0; destlen = (int)unilen; } return (destlen); } /* * Compare a CS0 dstring with a name passed in from the VFS layer. Return * 0 on a successful match, nonzero otherwise. Unicode work may need to be done * here also. */ static int udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct udf_mnt *udfmp) { char *transname; int error = 0; /* This is overkill, but not worth creating a new zone */ transname = uma_zalloc(udf_zone_trans, M_WAITOK); cs0len = udf_transname(cs0string, transname, cs0len, udfmp); /* Easy check. If they aren't the same length, they aren't equal */ if ((cs0len == 0) || (cs0len != cmplen)) error = -1; else error = bcmp(transname, cmpname, cmplen); uma_zfree(udf_zone_trans, transname); return (error); } struct udf_uiodir { struct dirent *dirent; uint64_t *cookies; int ncookies; int acookies; int eofflag; }; static int udf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie) { if (uiodir->cookies != NULL) { if (++uiodir->acookies > uiodir->ncookies) { uiodir->eofflag = 0; return (-1); } *uiodir->cookies++ = cookie; } if (uio->uio_resid < de_size) { uiodir->eofflag = 0; return (-1); } return (uiomove(uiodir->dirent, de_size, uio)); } static struct udf_dirstream * udf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp) { struct udf_dirstream *ds; ds = uma_zalloc(udf_zone_ds, M_WAITOK | M_ZERO); ds->node = node; ds->offset = offset; ds->udfmp = udfmp; ds->fsize = fsize; return (ds); } static struct fileid_desc * udf_getfid(struct udf_dirstream *ds) { struct fileid_desc *fid; int error, frag_size = 0, total_fid_size; /* End of directory? */ if (ds->offset + ds->off >= ds->fsize) { ds->error = 0; return (NULL); } /* Grab the first extent of the directory */ if (ds->off == 0) { ds->size = 0; error = udf_readatoffset(ds->node, &ds->size, ds->offset, &ds->bp, &ds->data); if (error) { ds->error = error; if (ds->bp != NULL) brelse(ds->bp); return (NULL); } } /* * Clean up from a previous fragmented FID. * XXX Is this the right place for this? */ if (ds->fid_fragment && ds->buf != NULL) { ds->fid_fragment = 0; free(ds->buf, M_UDFFID); } fid = (struct fileid_desc*)&ds->data[ds->off]; /* * Check to see if the fid is fragmented. The first test * ensures that we don't wander off the end of the buffer * looking for the l_iu and l_fi fields. */ if (ds->off + UDF_FID_SIZE > ds->size || ds->off + le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){ /* Copy what we have of the fid into a buffer */ frag_size = ds->size - ds->off; if (frag_size >= ds->udfmp->bsize) { printf("udf: invalid FID fragment\n"); ds->error = EINVAL; return (NULL); } /* * File ID descriptors can only be at most one * logical sector in size. */ ds->buf = malloc(ds->udfmp->bsize, M_UDFFID, M_WAITOK | M_ZERO); bcopy(fid, ds->buf, frag_size); /* Reduce all of the casting magic */ fid = (struct fileid_desc*)ds->buf; if (ds->bp != NULL) brelse(ds->bp); /* Fetch the next allocation */ ds->offset += ds->size; ds->size = 0; error = udf_readatoffset(ds->node, &ds->size, ds->offset, &ds->bp, &ds->data); if (error) { ds->error = error; return (NULL); } /* * If the fragment was so small that we didn't get * the l_iu and l_fi fields, copy those in. */ if (frag_size < UDF_FID_SIZE) bcopy(ds->data, &ds->buf[frag_size], UDF_FID_SIZE - frag_size); /* * Now that we have enough of the fid to work with, * copy in the rest of the fid from the new * allocation. */ total_fid_size = UDF_FID_SIZE + le16toh(fid->l_iu) + fid->l_fi; if (total_fid_size > ds->udfmp->bsize) { printf("udf: invalid FID\n"); ds->error = EIO; return (NULL); } bcopy(ds->data, &ds->buf[frag_size], total_fid_size - frag_size); ds->fid_fragment = 1; } else { total_fid_size = le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE; } /* * Update the offset. Align on a 4 byte boundary because the * UDF spec says so. */ ds->this_off = ds->offset + ds->off; if (!ds->fid_fragment) { ds->off += (total_fid_size + 3) & ~0x03; } else { ds->off = (total_fid_size - frag_size + 3) & ~0x03; } return (fid); } static void udf_closedir(struct udf_dirstream *ds) { if (ds->bp != NULL) brelse(ds->bp); if (ds->fid_fragment && ds->buf != NULL) free(ds->buf, M_UDFFID); uma_zfree(udf_zone_ds, ds); } static int udf_readdir(struct vop_readdir_args *a) { struct vnode *vp; struct uio *uio; struct dirent dir; struct udf_node *node; struct udf_mnt *udfmp; struct fileid_desc *fid; struct udf_uiodir uiodir; struct udf_dirstream *ds; uint64_t *cookies = NULL; uint64_t len; int ncookies; int error = 0; vp = a->a_vp; uio = a->a_uio; node = VTON(vp); udfmp = node->udfmp; uiodir.eofflag = 1; if (a->a_ncookies != NULL) { /* * Guess how many entries are needed. If we run out, this * function will be called again and thing will pick up were * it left off. */ ncookies = uio->uio_resid / 8; cookies = malloc(sizeof(*cookies) * ncookies, M_TEMP, M_WAITOK); uiodir.ncookies = ncookies; uiodir.cookies = cookies; uiodir.acookies = 0; } else { uiodir.cookies = NULL; } /* * Iterate through the file id descriptors. Give the parent dir * entry special attention. */ len = le64toh(node->fentry->inf_len); if (len > INT_MAX) { /* too big, just cap to INT_MAX */ len = INT_MAX; } ds = udf_opendir(node, uio->uio_offset, len, node->udfmp); while ((fid = udf_getfid(ds)) != NULL) { /* XXX Should we return an error on a bad fid? */ if (udf_checktag(&fid->tag, TAGID_FID)) { printf("Invalid FID tag\n"); hexdump(fid, UDF_FID_SIZE, NULL, 0); error = EIO; break; } /* Is this a deleted file? */ if (fid->file_char & UDF_FILE_CHAR_DEL) continue; if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { /* Do up the '.' and '..' entries. Dummy values are * used for the cookies since the offset here is * usually zero, and NFS doesn't like that value */ dir.d_fileno = node->hash_id; dir.d_type = DT_DIR; dir.d_name[0] = '.'; dir.d_namlen = 1; dir.d_reclen = GENERIC_DIRSIZ(&dir); dir.d_off = 1; dirent_terminate(&dir); uiodir.dirent = &dir; error = udf_uiodir(&uiodir, dir.d_reclen, uio, 1); if (error) break; dir.d_fileno = udf_getid(&fid->icb); dir.d_type = DT_DIR; dir.d_name[0] = '.'; dir.d_name[1] = '.'; dir.d_namlen = 2; dir.d_reclen = GENERIC_DIRSIZ(&dir); dir.d_off = 2; dirent_terminate(&dir); uiodir.dirent = &dir; error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2); } else { dir.d_namlen = udf_transname(&fid->data[fid->l_iu], &dir.d_name[0], fid->l_fi, udfmp); dir.d_fileno = udf_getid(&fid->icb); dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ? DT_DIR : DT_UNKNOWN; dir.d_reclen = GENERIC_DIRSIZ(&dir); dir.d_off = ds->this_off; dirent_terminate(&dir); uiodir.dirent = &dir; error = udf_uiodir(&uiodir, dir.d_reclen, uio, ds->this_off); } if (error) break; uio->uio_offset = ds->offset + ds->off; } /* tell the calling layer whether we need to be called again */ *a->a_eofflag = uiodir.eofflag; if (error < 0) error = 0; if (!error) error = ds->error; udf_closedir(ds); if (a->a_ncookies != NULL) { if (error) free(cookies, M_TEMP); else { *a->a_ncookies = uiodir.acookies; *a->a_cookies = cookies; } } return (error); } static int udf_readlink(struct vop_readlink_args *ap) { struct path_component *pc, *end; struct vnode *vp; struct uio uio; struct iovec iov[1]; struct udf_node *node; void *buf; char *cp; uint64_t len; int error, root; /* * A symbolic link in UDF is a list of variable-length path * component structures. We build a pathname in the caller's * uio by traversing this list. */ vp = ap->a_vp; node = VTON(vp); len = le64toh(node->fentry->inf_len); if (len > MAXPATHLEN) return (EIO); buf = malloc(len, M_DEVBUF, M_WAITOK); iov[0].iov_len = len; iov[0].iov_base = buf; uio.uio_iov = iov; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = iov[0].iov_len; uio.uio_segflg = UIO_SYSSPACE; uio.uio_rw = UIO_READ; uio.uio_td = curthread; error = VOP_READ(vp, &uio, 0, ap->a_cred); if (error) goto error; pc = buf; end = (void *)((char *)buf + len); root = 0; while (pc < end) { switch (pc->type) { case UDF_PATH_ROOT: /* Only allow this at the beginning of a path. */ if ((void *)pc != buf) { error = EINVAL; goto error; } cp = "/"; len = 1; root = 1; break; case UDF_PATH_DOT: cp = "."; len = 1; break; case UDF_PATH_DOTDOT: cp = ".."; len = 2; break; case UDF_PATH_PATH: if (pc->length == 0) { error = EINVAL; goto error; } /* * XXX: We only support CS8 which appears to map * to ASCII directly. */ switch (pc->identifier[0]) { case 8: cp = pc->identifier + 1; len = pc->length - 1; break; default: error = EOPNOTSUPP; goto error; } break; default: error = EINVAL; goto error; } /* * If this is not the first component, insert a path * separator. */ if (pc != buf) { /* If we started with root we already have a "/". */ if (root) goto skipslash; root = 0; if (ap->a_uio->uio_resid < 1) { error = ENAMETOOLONG; goto error; } error = uiomove("/", 1, ap->a_uio); if (error) break; } skipslash: /* Append string at 'cp' of length 'len' to our path. */ if (len > ap->a_uio->uio_resid) { error = ENAMETOOLONG; goto error; } error = uiomove(cp, len, ap->a_uio); if (error) break; /* Advance to next component. */ pc = (void *)((char *)pc + 4 + pc->length); } error: free(buf, M_DEVBUF); return (error); } static int udf_strategy(struct vop_strategy_args *a) { struct buf *bp; struct vnode *vp; struct udf_node *node; struct bufobj *bo; off_t offset; uint32_t maxsize; daddr_t sector; int error; bp = a->a_bp; vp = a->a_vp; node = VTON(vp); if (bp->b_blkno == bp->b_lblkno) { offset = lblktosize(node->udfmp, bp->b_lblkno); error = udf_bmap_internal(node, offset, §or, &maxsize); if (error) { clrbuf(bp); bp->b_blkno = -1; bufdone(bp); return (0); } /* bmap gives sector numbers, bio works with device blocks */ bp->b_blkno = sector << (node->udfmp->bshift - DEV_BSHIFT); } bo = node->udfmp->im_bo; bp->b_iooffset = dbtob(bp->b_blkno); BO_STRATEGY(bo, bp); return (0); } static int udf_bmap(struct vop_bmap_args *a) { struct udf_node *node; uint32_t max_size; daddr_t lsector; int nblk; int error; node = VTON(a->a_vp); if (a->a_bop != NULL) *a->a_bop = &node->udfmp->im_devvp->v_bufobj; if (a->a_bnp == NULL) return (0); if (a->a_runb) *a->a_runb = 0; /* * UDF_INVALID_BMAP means data embedded into fentry, this is an internal * error that should not be propagated to calling code. * Most obvious mapping for this error is EOPNOTSUPP as we can not truly * translate block numbers in this case. * Incidentally, this return code will make vnode pager to use VOP_READ * to get data for mmap-ed pages and udf_read knows how to do the right * thing for this kind of files. */ error = udf_bmap_internal(node, a->a_bn << node->udfmp->bshift, &lsector, &max_size); if (error == UDF_INVALID_BMAP) return (EOPNOTSUPP); if (error) return (error); /* Translate logical to physical sector number */ *a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT); /* * Determine maximum number of readahead blocks following the * requested block. */ if (a->a_runp) { nblk = (max_size >> node->udfmp->bshift) - 1; if (nblk <= 0) *a->a_runp = 0; else if (nblk >= (MAXBSIZE >> node->udfmp->bshift)) *a->a_runp = (MAXBSIZE >> node->udfmp->bshift) - 1; else *a->a_runp = nblk; } if (a->a_runb) { *a->a_runb = 0; } return (0); } /* * The all powerful VOP_LOOKUP(). */ static int udf_lookup(struct vop_cachedlookup_args *a) { struct vnode *dvp; struct vnode *tdp = NULL; struct vnode **vpp = a->a_vpp; struct udf_node *node; struct udf_mnt *udfmp; struct fileid_desc *fid = NULL; struct udf_dirstream *ds; uint64_t fsize; u_long nameiop; u_long flags; char *nameptr; long namelen; ino_t id = 0; int offset, error = 0; int lkflags, ltype, numdirpasses; dvp = a->a_dvp; node = VTON(dvp); udfmp = node->udfmp; nameiop = a->a_cnp->cn_nameiop; flags = a->a_cnp->cn_flags; lkflags = a->a_cnp->cn_lkflags; nameptr = a->a_cnp->cn_nameptr; namelen = a->a_cnp->cn_namelen; fsize = le64toh(node->fentry->inf_len); if (fsize > INT_MAX) { /* too big, just cap to INT_MAX */ fsize = INT_MAX; } /* * If this is a LOOKUP and we've already partially searched through * the directory, pick up where we left off and flag that the * directory may need to be searched twice. For a full description, * see /sys/fs/cd9660/cd9660_lookup.c:cd9660_lookup() */ if (nameiop != LOOKUP || node->diroff == 0 || node->diroff > fsize) { offset = 0; numdirpasses = 1; } else { offset = node->diroff; numdirpasses = 2; nchstats.ncs_2passes++; } lookloop: ds = udf_opendir(node, offset, fsize, udfmp); while ((fid = udf_getfid(ds)) != NULL) { /* XXX Should we return an error on a bad fid? */ if (udf_checktag(&fid->tag, TAGID_FID)) { printf("udf_lookup: Invalid tag\n"); error = EIO; break; } /* Is this a deleted file? */ if (fid->file_char & UDF_FILE_CHAR_DEL) continue; if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { if (flags & ISDOTDOT) { id = udf_getid(&fid->icb); break; } } else { if (!(udf_cmpname(&fid->data[fid->l_iu], nameptr, fid->l_fi, namelen, udfmp))) { id = udf_getid(&fid->icb); break; } } } if (!error) error = ds->error; /* XXX Bail out here? */ if (error) { udf_closedir(ds); return (error); } /* Did we have a match? */ if (id) { /* * Remember where this entry was if it's the final * component. */ if ((flags & ISLASTCN) && nameiop == LOOKUP) node->diroff = ds->offset + ds->off; if (numdirpasses == 2) nchstats.ncs_pass2++; udf_closedir(ds); if (flags & ISDOTDOT) { error = vn_vget_ino(dvp, id, lkflags, &tdp); } else if (node->hash_id == id) { - VREF(dvp); /* we want ourself, ie "." */ + vref(dvp); /* we want ourself, ie "." */ /* * When we lookup "." we still can be asked to lock it * differently. */ ltype = lkflags & LK_TYPE_MASK; if (ltype != VOP_ISLOCKED(dvp)) { if (ltype == LK_EXCLUSIVE) vn_lock(dvp, LK_UPGRADE | LK_RETRY); else /* if (ltype == LK_SHARED) */ vn_lock(dvp, LK_DOWNGRADE | LK_RETRY); } tdp = dvp; } else error = udf_vget(udfmp->im_mountp, id, lkflags, &tdp); if (!error) { *vpp = tdp; /* Put this entry in the cache */ if (flags & MAKEENTRY) cache_enter(dvp, *vpp, a->a_cnp); } } else { /* Name wasn't found on this pass. Do another pass? */ if (numdirpasses == 2) { numdirpasses--; offset = 0; udf_closedir(ds); goto lookloop; } udf_closedir(ds); /* Enter name into cache as non-existant */ if (flags & MAKEENTRY) cache_enter(dvp, *vpp, a->a_cnp); if ((flags & ISLASTCN) && (nameiop == CREATE || nameiop == RENAME)) { error = EROFS; } else { error = ENOENT; } } return (error); } static int udf_reclaim(struct vop_reclaim_args *a) { struct vnode *vp; struct udf_node *unode; vp = a->a_vp; unode = VTON(vp); if (unode != NULL) { vfs_hash_remove(vp); if (unode->fentry != NULL) free(unode->fentry, M_UDFFENTRY); uma_zfree(udf_zone_node, unode); vp->v_data = NULL; } return (0); } static int udf_vptofh(struct vop_vptofh_args *a) { struct udf_node *node; struct ifid *ifhp; _Static_assert(sizeof(struct ifid) <= sizeof(struct fid), "struct ifid cannot be larger than struct fid"); node = VTON(a->a_vp); ifhp = (struct ifid *)a->a_fhp; ifhp->ifid_len = sizeof(struct ifid); ifhp->ifid_ino = node->hash_id; return (0); } /* * Read the block and then set the data pointer to correspond with the * offset passed in. Only read in at most 'size' bytes, and then set 'size' * to the number of bytes pointed to. If 'size' is zero, try to read in a * whole extent. * * Note that *bp may be assigned error or not. * */ static int udf_readatoffset(struct udf_node *node, int *size, off_t offset, struct buf **bp, uint8_t **data) { struct udf_mnt *udfmp = node->udfmp; struct vnode *vp = node->i_vnode; struct file_entry *fentry; struct buf *bp1; uint32_t max_size; daddr_t sector; off_t off; int adj_size; int error; /* * This call is made *not* only to detect UDF_INVALID_BMAP case, * max_size is used as an ad-hoc read-ahead hint for "normal" case. */ error = udf_bmap_internal(node, offset, §or, &max_size); if (error == UDF_INVALID_BMAP) { /* * This error means that the file *data* is stored in the * allocation descriptor field of the file entry. */ fentry = node->fentry; *data = &fentry->data[le32toh(fentry->l_ea)]; *size = le32toh(fentry->l_ad); if (offset >= *size) *size = 0; else { *data += offset; *size -= offset; } return (0); } else if (error != 0) { return (error); } /* Adjust the size so that it is within range */ if (*size == 0 || *size > max_size) *size = max_size; /* * Because we will read starting at block boundary, we need to adjust * how much we need to read so that all promised data is in. * Also, we can't promise to read more than MAXBSIZE bytes starting * from block boundary, so adjust what we promise too. */ off = blkoff(udfmp, offset); *size = min(*size, MAXBSIZE - off); adj_size = (*size + off + udfmp->bmask) & ~udfmp->bmask; *bp = NULL; if ((error = bread(vp, lblkno(udfmp, offset), adj_size, NOCRED, bp))) { printf("warning: udf_readlblks returned error %d\n", error); /* note: *bp may be non-NULL */ return (error); } bp1 = *bp; *data = (uint8_t *)&bp1->b_data[offset & udfmp->bmask]; return (0); } /* * Translate a file offset into a logical block and then into a physical * block. * max_size - maximum number of bytes that can be read starting from given * offset, rather than beginning of calculated sector number */ static int udf_bmap_internal(struct udf_node *node, off_t offset, daddr_t *sector, uint32_t *max_size) { struct udf_mnt *udfmp; struct file_entry *fentry; void *icb; struct icb_tag *tag; uint32_t icblen = 0; daddr_t lsector; int ad_offset, ad_num = 0; int i, p_offset; udfmp = node->udfmp; fentry = node->fentry; tag = &fentry->icbtag; switch (le16toh(tag->strat_type)) { case 4: break; case 4096: printf("Cannot deal with strategy4096 yet!\n"); return (ENODEV); default: printf("Unknown strategy type %d\n", tag->strat_type); return (ENODEV); } switch (le16toh(tag->flags) & 0x7) { case 0: /* * The allocation descriptor field is filled with short_ad's. * If the offset is beyond the current extent, look for the * next extent. */ do { offset -= icblen; ad_offset = sizeof(struct short_ad) * ad_num; if (ad_offset > le32toh(fentry->l_ad)) { printf("File offset out of bounds\n"); return (EINVAL); } icb = GETICB(short_ad, fentry, le32toh(fentry->l_ea) + ad_offset); icblen = GETICBLEN(short_ad, icb); ad_num++; } while(offset >= icblen); lsector = (offset >> udfmp->bshift) + le32toh(((struct short_ad *)(icb))->pos); *max_size = icblen - offset; break; case 1: /* * The allocation descriptor field is filled with long_ad's * If the offset is beyond the current extent, look for the * next extent. */ do { offset -= icblen; ad_offset = sizeof(struct long_ad) * ad_num; if (ad_offset > le32toh(fentry->l_ad)) { printf("File offset out of bounds\n"); return (EINVAL); } icb = GETICB(long_ad, fentry, le32toh(fentry->l_ea) + ad_offset); icblen = GETICBLEN(long_ad, icb); ad_num++; } while(offset >= icblen); lsector = (offset >> udfmp->bshift) + le32toh(((struct long_ad *)(icb))->loc.lb_num); *max_size = icblen - offset; break; case 3: /* * This type means that the file *data* is stored in the * allocation descriptor field of the file entry. */ *max_size = 0; *sector = node->hash_id + udfmp->part_start; return (UDF_INVALID_BMAP); case 2: /* DirectCD does not use extended_ad's */ default: printf("Unsupported allocation descriptor %d\n", tag->flags & 0x7); return (ENODEV); } *sector = lsector + udfmp->part_start; /* * Check the sparing table. Each entry represents the beginning of * a packet. */ if (udfmp->s_table != NULL) { for (i = 0; i< udfmp->s_table_entries; i++) { p_offset = lsector - le32toh(udfmp->s_table->entries[i].org); if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) { *sector = le32toh(udfmp->s_table->entries[i].map) + p_offset; break; } } } return (0); } diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index 568d8b56d0be..a8aec397b352 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -1,2954 +1,2954 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2005 David Xu * Copyright (c) 2016-2017 Robert N. M. Watson * All rights reserved. * * Portions of this software were developed by BAE Systems, the University of * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent * Computing (TC) research program. * * 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. * */ /* * POSIX message queue implementation. * * 1) A mqueue filesystem can be mounted, each message queue appears * in mounted directory, user can change queue's permission and * ownership, or remove a queue. Manually creating a file in the * directory causes a message queue to be created in the kernel with * default message queue attributes applied and same name used, this * method is not advocated since mq_open syscall allows user to specify * different attributes. Also the file system can be mounted multiple * times at different mount points but shows same contents. * * 2) Standard POSIX message queue API. The syscalls do not use vfs layer, * but directly operate on internal data structure, this allows user to * use the IPC facility without having to mount mqueue file system. */ #include "opt_capsicum.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include FEATURE(p1003_1b_mqueue, "POSIX P1003.1B message queues support"); /* * Limits and constants */ #define MQFS_NAMELEN NAME_MAX #define MQFS_DELEN (8 + MQFS_NAMELEN) /* node types */ typedef enum { mqfstype_none = 0, mqfstype_root, mqfstype_dir, mqfstype_this, mqfstype_parent, mqfstype_file, mqfstype_symlink, } mqfs_type_t; struct mqfs_node; /* * mqfs_info: describes a mqfs instance */ struct mqfs_info { struct sx mi_lock; struct mqfs_node *mi_root; struct unrhdr *mi_unrhdr; }; struct mqfs_vdata { LIST_ENTRY(mqfs_vdata) mv_link; struct mqfs_node *mv_node; struct vnode *mv_vnode; struct task mv_task; }; /* * mqfs_node: describes a node (file or directory) within a mqfs */ struct mqfs_node { char mn_name[MQFS_NAMELEN+1]; struct mqfs_info *mn_info; struct mqfs_node *mn_parent; LIST_HEAD(,mqfs_node) mn_children; LIST_ENTRY(mqfs_node) mn_sibling; LIST_HEAD(,mqfs_vdata) mn_vnodes; const void *mn_pr_root; int mn_refcount; mqfs_type_t mn_type; int mn_deleted; uint32_t mn_fileno; void *mn_data; struct timespec mn_birth; struct timespec mn_ctime; struct timespec mn_atime; struct timespec mn_mtime; uid_t mn_uid; gid_t mn_gid; int mn_mode; }; #define VTON(vp) (((struct mqfs_vdata *)((vp)->v_data))->mv_node) #define VTOMQ(vp) ((struct mqueue *)(VTON(vp)->mn_data)) #define VFSTOMQFS(m) ((struct mqfs_info *)((m)->mnt_data)) #define FPTOMQ(fp) ((struct mqueue *)(((struct mqfs_node *) \ (fp)->f_data)->mn_data)) TAILQ_HEAD(msgq, mqueue_msg); struct mqueue; struct mqueue_notifier { LIST_ENTRY(mqueue_notifier) nt_link; struct sigevent nt_sigev; ksiginfo_t nt_ksi; struct proc *nt_proc; }; struct mqueue { struct mtx mq_mutex; int mq_flags; long mq_maxmsg; long mq_msgsize; long mq_curmsgs; long mq_totalbytes; struct msgq mq_msgq; int mq_receivers; int mq_senders; struct selinfo mq_rsel; struct selinfo mq_wsel; struct mqueue_notifier *mq_notifier; }; #define MQ_RSEL 0x01 #define MQ_WSEL 0x02 struct mqueue_msg { TAILQ_ENTRY(mqueue_msg) msg_link; unsigned int msg_prio; unsigned int msg_size; /* following real data... */ }; static SYSCTL_NODE(_kern, OID_AUTO, mqueue, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "POSIX real time message queue"); static int default_maxmsg = 10; SYSCTL_INT(_kern_mqueue, OID_AUTO, default_maxmsg, CTLFLAG_RD, &default_maxmsg, 0, "Default maximum messages in queue"); static int default_msgsize = 1024; SYSCTL_INT(_kern_mqueue, OID_AUTO, default_msgsize, CTLFLAG_RD, &default_msgsize, 0, "Default maximum message size"); static int maxmsg = 100; SYSCTL_INT(_kern_mqueue, OID_AUTO, maxmsg, CTLFLAG_RW, &maxmsg, 0, "maximum messages in queue"); static int maxmsgsize = 16384; SYSCTL_INT(_kern_mqueue, OID_AUTO, maxmsgsize, CTLFLAG_RW, &maxmsgsize, 0, "maximum message size"); static int maxmq = 100; SYSCTL_INT(_kern_mqueue, OID_AUTO, maxmq, CTLFLAG_RW, &maxmq, 0, "maximum message queues"); static int curmq = 0; SYSCTL_INT(_kern_mqueue, OID_AUTO, curmq, CTLFLAG_RW, &curmq, 0, "current message queue number"); static int unloadable = 0; static MALLOC_DEFINE(M_MQUEUEDATA, "mqdata", "mqueue data"); static eventhandler_tag exit_tag; /* Only one instance per-system */ static struct mqfs_info mqfs_data; static uma_zone_t mqnode_zone; static uma_zone_t mqueue_zone; static uma_zone_t mvdata_zone; static uma_zone_t mqnoti_zone; static struct vop_vector mqfs_vnodeops; static const struct fileops mqueueops; static unsigned mqfs_osd_jail_slot; /* * Directory structure construction and manipulation */ #ifdef notyet static struct mqfs_node *mqfs_create_dir(struct mqfs_node *parent, const char *name, int namelen, struct ucred *cred, int mode); static struct mqfs_node *mqfs_create_link(struct mqfs_node *parent, const char *name, int namelen, struct ucred *cred, int mode); #endif static struct mqfs_node *mqfs_create_file(struct mqfs_node *parent, const char *name, int namelen, struct ucred *cred, int mode); static int mqfs_destroy(struct mqfs_node *mn); static void mqfs_fileno_alloc(struct mqfs_info *mi, struct mqfs_node *mn); static void mqfs_fileno_free(struct mqfs_info *mi, struct mqfs_node *mn); static int mqfs_allocv(struct mount *mp, struct vnode **vpp, struct mqfs_node *pn); static int mqfs_prison_remove(void *obj, void *data); /* * Message queue construction and maniplation */ static struct mqueue *mqueue_alloc(const struct mq_attr *attr); static void mqueue_free(struct mqueue *mq); static int mqueue_send(struct mqueue *mq, const char *msg_ptr, size_t msg_len, unsigned msg_prio, int waitok, const struct timespec *abs_timeout); static int mqueue_receive(struct mqueue *mq, char *msg_ptr, size_t msg_len, unsigned *msg_prio, int waitok, const struct timespec *abs_timeout); static int _mqueue_send(struct mqueue *mq, struct mqueue_msg *msg, int timo); static int _mqueue_recv(struct mqueue *mq, struct mqueue_msg **msg, int timo); static void mqueue_send_notification(struct mqueue *mq); static void mqueue_fdclose(struct thread *td, int fd, struct file *fp); static void mq_proc_exit(void *arg, struct proc *p); /* * kqueue filters */ static void filt_mqdetach(struct knote *kn); static int filt_mqread(struct knote *kn, long hint); static int filt_mqwrite(struct knote *kn, long hint); static const struct filterops mq_rfiltops = { .f_isfd = 1, .f_detach = filt_mqdetach, .f_event = filt_mqread, }; static const struct filterops mq_wfiltops = { .f_isfd = 1, .f_detach = filt_mqdetach, .f_event = filt_mqwrite, }; /* * Initialize fileno bitmap */ static void mqfs_fileno_init(struct mqfs_info *mi) { struct unrhdr *up; up = new_unrhdr(1, INT_MAX, NULL); mi->mi_unrhdr = up; } /* * Tear down fileno bitmap */ static void mqfs_fileno_uninit(struct mqfs_info *mi) { struct unrhdr *up; up = mi->mi_unrhdr; mi->mi_unrhdr = NULL; delete_unrhdr(up); } /* * Allocate a file number */ static void mqfs_fileno_alloc(struct mqfs_info *mi, struct mqfs_node *mn) { /* make sure our parent has a file number */ if (mn->mn_parent && !mn->mn_parent->mn_fileno) mqfs_fileno_alloc(mi, mn->mn_parent); switch (mn->mn_type) { case mqfstype_root: case mqfstype_dir: case mqfstype_file: case mqfstype_symlink: mn->mn_fileno = alloc_unr(mi->mi_unrhdr); break; case mqfstype_this: KASSERT(mn->mn_parent != NULL, ("mqfstype_this node has no parent")); mn->mn_fileno = mn->mn_parent->mn_fileno; break; case mqfstype_parent: KASSERT(mn->mn_parent != NULL, ("mqfstype_parent node has no parent")); if (mn->mn_parent == mi->mi_root) { mn->mn_fileno = mn->mn_parent->mn_fileno; break; } KASSERT(mn->mn_parent->mn_parent != NULL, ("mqfstype_parent node has no grandparent")); mn->mn_fileno = mn->mn_parent->mn_parent->mn_fileno; break; default: KASSERT(0, ("mqfs_fileno_alloc() called for unknown type node: %d", mn->mn_type)); break; } } /* * Release a file number */ static void mqfs_fileno_free(struct mqfs_info *mi, struct mqfs_node *mn) { switch (mn->mn_type) { case mqfstype_root: case mqfstype_dir: case mqfstype_file: case mqfstype_symlink: free_unr(mi->mi_unrhdr, mn->mn_fileno); break; case mqfstype_this: case mqfstype_parent: /* ignore these, as they don't "own" their file number */ break; default: KASSERT(0, ("mqfs_fileno_free() called for unknown type node: %d", mn->mn_type)); break; } } static __inline struct mqfs_node * mqnode_alloc(void) { return (uma_zalloc(mqnode_zone, M_WAITOK | M_ZERO)); } static __inline void mqnode_free(struct mqfs_node *node) { uma_zfree(mqnode_zone, node); } static __inline void mqnode_addref(struct mqfs_node *node) { atomic_add_int(&node->mn_refcount, 1); } static __inline void mqnode_release(struct mqfs_node *node) { struct mqfs_info *mqfs; int old, exp; mqfs = node->mn_info; old = atomic_fetchadd_int(&node->mn_refcount, -1); if (node->mn_type == mqfstype_dir || node->mn_type == mqfstype_root) exp = 3; /* include . and .. */ else exp = 1; if (old == exp) { int locked = sx_xlocked(&mqfs->mi_lock); if (!locked) sx_xlock(&mqfs->mi_lock); mqfs_destroy(node); if (!locked) sx_xunlock(&mqfs->mi_lock); } } /* * Add a node to a directory */ static int mqfs_add_node(struct mqfs_node *parent, struct mqfs_node *node) { KASSERT(parent != NULL, ("%s(): parent is NULL", __func__)); KASSERT(parent->mn_info != NULL, ("%s(): parent has no mn_info", __func__)); KASSERT(parent->mn_type == mqfstype_dir || parent->mn_type == mqfstype_root, ("%s(): parent is not a directory", __func__)); node->mn_info = parent->mn_info; node->mn_parent = parent; LIST_INIT(&node->mn_children); LIST_INIT(&node->mn_vnodes); LIST_INSERT_HEAD(&parent->mn_children, node, mn_sibling); mqnode_addref(parent); return (0); } static struct mqfs_node * mqfs_create_node(const char *name, int namelen, struct ucred *cred, int mode, int nodetype) { struct mqfs_node *node; node = mqnode_alloc(); strncpy(node->mn_name, name, namelen); node->mn_pr_root = cred->cr_prison->pr_root; node->mn_type = nodetype; node->mn_refcount = 1; vfs_timestamp(&node->mn_birth); node->mn_ctime = node->mn_atime = node->mn_mtime = node->mn_birth; node->mn_uid = cred->cr_uid; node->mn_gid = cred->cr_gid; node->mn_mode = mode; return (node); } /* * Create a file */ static struct mqfs_node * mqfs_create_file(struct mqfs_node *parent, const char *name, int namelen, struct ucred *cred, int mode) { struct mqfs_node *node; node = mqfs_create_node(name, namelen, cred, mode, mqfstype_file); if (mqfs_add_node(parent, node) != 0) { mqnode_free(node); return (NULL); } return (node); } /* * Add . and .. to a directory */ static int mqfs_fixup_dir(struct mqfs_node *parent) { struct mqfs_node *dir; dir = mqnode_alloc(); dir->mn_name[0] = '.'; dir->mn_type = mqfstype_this; dir->mn_refcount = 1; if (mqfs_add_node(parent, dir) != 0) { mqnode_free(dir); return (-1); } dir = mqnode_alloc(); dir->mn_name[0] = dir->mn_name[1] = '.'; dir->mn_type = mqfstype_parent; dir->mn_refcount = 1; if (mqfs_add_node(parent, dir) != 0) { mqnode_free(dir); return (-1); } return (0); } #ifdef notyet /* * Create a directory */ static struct mqfs_node * mqfs_create_dir(struct mqfs_node *parent, const char *name, int namelen, struct ucred *cred, int mode) { struct mqfs_node *node; node = mqfs_create_node(name, namelen, cred, mode, mqfstype_dir); if (mqfs_add_node(parent, node) != 0) { mqnode_free(node); return (NULL); } if (mqfs_fixup_dir(node) != 0) { mqfs_destroy(node); return (NULL); } return (node); } /* * Create a symlink */ static struct mqfs_node * mqfs_create_link(struct mqfs_node *parent, const char *name, int namelen, struct ucred *cred, int mode) { struct mqfs_node *node; node = mqfs_create_node(name, namelen, cred, mode, mqfstype_symlink); if (mqfs_add_node(parent, node) != 0) { mqnode_free(node); return (NULL); } return (node); } #endif /* * Destroy a node or a tree of nodes */ static int mqfs_destroy(struct mqfs_node *node) { struct mqfs_node *parent; KASSERT(node != NULL, ("%s(): node is NULL", __func__)); KASSERT(node->mn_info != NULL, ("%s(): node has no mn_info", __func__)); /* destroy children */ if (node->mn_type == mqfstype_dir || node->mn_type == mqfstype_root) while (! LIST_EMPTY(&node->mn_children)) mqfs_destroy(LIST_FIRST(&node->mn_children)); /* unlink from parent */ if ((parent = node->mn_parent) != NULL) { KASSERT(parent->mn_info == node->mn_info, ("%s(): parent has different mn_info", __func__)); LIST_REMOVE(node, mn_sibling); } if (node->mn_fileno != 0) mqfs_fileno_free(node->mn_info, node); if (node->mn_data != NULL) mqueue_free(node->mn_data); mqnode_free(node); return (0); } /* * Mount a mqfs instance */ static int mqfs_mount(struct mount *mp) { struct statfs *sbp; if (mp->mnt_flag & MNT_UPDATE) return (EOPNOTSUPP); mp->mnt_data = &mqfs_data; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; MNT_IUNLOCK(mp); vfs_getnewfsid(mp); sbp = &mp->mnt_stat; vfs_mountedfrom(mp, "mqueue"); sbp->f_bsize = PAGE_SIZE; sbp->f_iosize = PAGE_SIZE; sbp->f_blocks = 1; sbp->f_bfree = 1; sbp->f_bavail = 0; sbp->f_files = 0; sbp->f_ffree = 0; return (0); } /* * Unmount a mqfs instance */ static int mqfs_unmount(struct mount *mp, int mntflags) { int error; error = vflush(mp, 0, (mntflags & MNT_FORCE) ? FORCECLOSE : 0, curthread); return (error); } /* * Return a root vnode */ static int mqfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct mqfs_info *mqfs; int ret; mqfs = VFSTOMQFS(mp); ret = mqfs_allocv(mp, vpp, mqfs->mi_root); return (ret); } /* * Return filesystem stats */ static int mqfs_statfs(struct mount *mp, struct statfs *sbp) { /* XXX update statistics */ return (0); } /* * Initialize a mqfs instance */ static int mqfs_init(struct vfsconf *vfc) { struct mqfs_node *root; struct mqfs_info *mi; osd_method_t methods[PR_MAXMETHOD] = { [PR_METHOD_REMOVE] = mqfs_prison_remove, }; mqnode_zone = uma_zcreate("mqnode", sizeof(struct mqfs_node), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); mqueue_zone = uma_zcreate("mqueue", sizeof(struct mqueue), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); mvdata_zone = uma_zcreate("mvdata", sizeof(struct mqfs_vdata), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); mqnoti_zone = uma_zcreate("mqnotifier", sizeof(struct mqueue_notifier), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); mi = &mqfs_data; sx_init(&mi->mi_lock, "mqfs lock"); /* set up the root diretory */ root = mqfs_create_node("/", 1, curthread->td_ucred, 01777, mqfstype_root); root->mn_info = mi; LIST_INIT(&root->mn_children); LIST_INIT(&root->mn_vnodes); mi->mi_root = root; mqfs_fileno_init(mi); mqfs_fileno_alloc(mi, root); mqfs_fixup_dir(root); exit_tag = EVENTHANDLER_REGISTER(process_exit, mq_proc_exit, NULL, EVENTHANDLER_PRI_ANY); mq_fdclose = mqueue_fdclose; p31b_setcfg(CTL_P1003_1B_MESSAGE_PASSING, _POSIX_MESSAGE_PASSING); mqfs_osd_jail_slot = osd_jail_register(NULL, methods); return (0); } /* * Destroy a mqfs instance */ static int mqfs_uninit(struct vfsconf *vfc) { struct mqfs_info *mi; if (!unloadable) return (EOPNOTSUPP); osd_jail_deregister(mqfs_osd_jail_slot); EVENTHANDLER_DEREGISTER(process_exit, exit_tag); mi = &mqfs_data; mqfs_destroy(mi->mi_root); mi->mi_root = NULL; mqfs_fileno_uninit(mi); sx_destroy(&mi->mi_lock); uma_zdestroy(mqnode_zone); uma_zdestroy(mqueue_zone); uma_zdestroy(mvdata_zone); uma_zdestroy(mqnoti_zone); return (0); } /* * task routine */ static void do_recycle(void *context, int pending __unused) { struct vnode *vp = (struct vnode *)context; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vrecycle(vp); VOP_UNLOCK(vp); vdrop(vp); } /* * Allocate a vnode */ static int mqfs_allocv(struct mount *mp, struct vnode **vpp, struct mqfs_node *pn) { struct mqfs_vdata *vd; struct mqfs_info *mqfs; struct vnode *newvpp; int error; mqfs = pn->mn_info; *vpp = NULL; sx_xlock(&mqfs->mi_lock); LIST_FOREACH(vd, &pn->mn_vnodes, mv_link) { if (vd->mv_vnode->v_mount == mp) { vhold(vd->mv_vnode); break; } } if (vd != NULL) { found: *vpp = vd->mv_vnode; sx_xunlock(&mqfs->mi_lock); error = vget(*vpp, LK_RETRY | LK_EXCLUSIVE); vdrop(*vpp); return (error); } sx_xunlock(&mqfs->mi_lock); error = getnewvnode("mqueue", mp, &mqfs_vnodeops, &newvpp); if (error) return (error); vn_lock(newvpp, LK_EXCLUSIVE | LK_RETRY); error = insmntque(newvpp, mp); if (error != 0) return (error); sx_xlock(&mqfs->mi_lock); /* * Check if it has already been allocated * while we were blocked. */ LIST_FOREACH(vd, &pn->mn_vnodes, mv_link) { if (vd->mv_vnode->v_mount == mp) { vhold(vd->mv_vnode); sx_xunlock(&mqfs->mi_lock); vgone(newvpp); vput(newvpp); goto found; } } *vpp = newvpp; vd = uma_zalloc(mvdata_zone, M_WAITOK); (*vpp)->v_data = vd; vd->mv_vnode = *vpp; vd->mv_node = pn; TASK_INIT(&vd->mv_task, 0, do_recycle, *vpp); LIST_INSERT_HEAD(&pn->mn_vnodes, vd, mv_link); mqnode_addref(pn); switch (pn->mn_type) { case mqfstype_root: (*vpp)->v_vflag = VV_ROOT; /* fall through */ case mqfstype_dir: case mqfstype_this: case mqfstype_parent: (*vpp)->v_type = VDIR; break; case mqfstype_file: (*vpp)->v_type = VREG; break; case mqfstype_symlink: (*vpp)->v_type = VLNK; break; case mqfstype_none: KASSERT(0, ("mqfs_allocf called for null node\n")); default: panic("%s has unexpected type: %d", pn->mn_name, pn->mn_type); } sx_xunlock(&mqfs->mi_lock); vn_set_state(*vpp, VSTATE_CONSTRUCTED); return (0); } /* * Search a directory entry */ static struct mqfs_node * mqfs_search(struct mqfs_node *pd, const char *name, int len, struct ucred *cred) { struct mqfs_node *pn; const void *pr_root; sx_assert(&pd->mn_info->mi_lock, SX_LOCKED); pr_root = cred->cr_prison->pr_root; LIST_FOREACH(pn, &pd->mn_children, mn_sibling) { /* Only match names within the same prison root directory */ if ((pn->mn_pr_root == NULL || pn->mn_pr_root == pr_root) && strncmp(pn->mn_name, name, len) == 0 && pn->mn_name[len] == '\0') return (pn); } return (NULL); } /* * Look up a file or directory. */ static int mqfs_lookupx(struct vop_cachedlookup_args *ap) { struct componentname *cnp; struct vnode *dvp, **vpp; struct mqfs_node *pd; struct mqfs_node *pn; struct mqfs_info *mqfs; uint64_t flags; int nameiop, error, namelen; char *pname; struct thread *td; td = curthread; cnp = ap->a_cnp; vpp = ap->a_vpp; dvp = ap->a_dvp; pname = cnp->cn_nameptr; namelen = cnp->cn_namelen; flags = cnp->cn_flags; nameiop = cnp->cn_nameiop; pd = VTON(dvp); pn = NULL; mqfs = pd->mn_info; *vpp = NULL; if (dvp->v_type != VDIR) return (ENOTDIR); error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); if (error) return (error); /* shortcut: check if the name is too long */ if (cnp->cn_namelen >= MQFS_NAMELEN) return (ENOENT); /* self */ if (namelen == 1 && pname[0] == '.') { if ((flags & ISLASTCN) && nameiop != LOOKUP) return (EINVAL); pn = pd; *vpp = dvp; - VREF(dvp); + vref(dvp); return (0); } /* parent */ if (cnp->cn_flags & ISDOTDOT) { if (dvp->v_vflag & VV_ROOT) return (EIO); if ((flags & ISLASTCN) && nameiop != LOOKUP) return (EINVAL); VOP_UNLOCK(dvp); KASSERT(pd->mn_parent, ("non-root directory has no parent")); pn = pd->mn_parent; error = mqfs_allocv(dvp->v_mount, vpp, pn); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); return (error); } /* named node */ sx_xlock(&mqfs->mi_lock); pn = mqfs_search(pd, pname, namelen, cnp->cn_cred); if (pn != NULL) mqnode_addref(pn); sx_xunlock(&mqfs->mi_lock); /* found */ if (pn != NULL) { /* DELETE */ if (nameiop == DELETE && (flags & ISLASTCN)) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); if (error) { mqnode_release(pn); return (error); } if (*vpp == dvp) { - VREF(dvp); + vref(dvp); *vpp = dvp; mqnode_release(pn); return (0); } } /* allocate vnode */ error = mqfs_allocv(dvp->v_mount, vpp, pn); mqnode_release(pn); if (error == 0 && cnp->cn_flags & MAKEENTRY) cache_enter(dvp, *vpp, cnp); return (error); } /* not found */ /* will create a new entry in the directory ? */ if ((nameiop == CREATE || nameiop == RENAME) && (flags & LOCKPARENT) && (flags & ISLASTCN)) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); if (error) return (error); return (EJUSTRETURN); } return (ENOENT); } #if 0 struct vop_lookup_args { struct vop_generic_args a_gen; struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; }; #endif /* * vnode lookup operation */ static int mqfs_lookup(struct vop_cachedlookup_args *ap) { int rc; rc = mqfs_lookupx(ap); return (rc); } #if 0 struct vop_create_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; }; #endif /* * vnode creation operation */ static int mqfs_create(struct vop_create_args *ap) { struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); struct componentname *cnp = ap->a_cnp; struct mqfs_node *pd; struct mqfs_node *pn; struct mqueue *mq; int error; pd = VTON(ap->a_dvp); if (pd->mn_type != mqfstype_root && pd->mn_type != mqfstype_dir) return (ENOTDIR); mq = mqueue_alloc(NULL); if (mq == NULL) return (EAGAIN); sx_xlock(&mqfs->mi_lock); pn = mqfs_create_file(pd, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred, ap->a_vap->va_mode); if (pn == NULL) { sx_xunlock(&mqfs->mi_lock); error = ENOSPC; } else { mqnode_addref(pn); sx_xunlock(&mqfs->mi_lock); error = mqfs_allocv(ap->a_dvp->v_mount, ap->a_vpp, pn); mqnode_release(pn); if (error) mqfs_destroy(pn); else pn->mn_data = mq; } if (error) mqueue_free(mq); return (error); } /* * Remove an entry */ static int do_unlink(struct mqfs_node *pn, struct ucred *ucred) { struct mqfs_node *parent; struct mqfs_vdata *vd; int error = 0; sx_assert(&pn->mn_info->mi_lock, SX_LOCKED); if (ucred->cr_uid != pn->mn_uid && (error = priv_check_cred(ucred, PRIV_MQ_ADMIN)) != 0) error = EACCES; else if (!pn->mn_deleted) { parent = pn->mn_parent; pn->mn_parent = NULL; pn->mn_deleted = 1; LIST_REMOVE(pn, mn_sibling); LIST_FOREACH(vd, &pn->mn_vnodes, mv_link) { cache_purge(vd->mv_vnode); vhold(vd->mv_vnode); taskqueue_enqueue(taskqueue_thread, &vd->mv_task); } mqnode_release(pn); mqnode_release(parent); } else error = ENOENT; return (error); } #if 0 struct vop_remove_args { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; }; #endif /* * vnode removal operation */ static int mqfs_remove(struct vop_remove_args *ap) { struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); struct mqfs_node *pn; int error; if (ap->a_vp->v_type == VDIR) return (EPERM); pn = VTON(ap->a_vp); sx_xlock(&mqfs->mi_lock); error = do_unlink(pn, ap->a_cnp->cn_cred); sx_xunlock(&mqfs->mi_lock); return (error); } #if 0 struct vop_inactive_args { struct vnode *a_vp; struct thread *a_td; }; #endif static int mqfs_inactive(struct vop_inactive_args *ap) { struct mqfs_node *pn = VTON(ap->a_vp); if (pn->mn_deleted) vrecycle(ap->a_vp); return (0); } #if 0 struct vop_reclaim_args { struct vop_generic_args a_gen; struct vnode *a_vp; }; #endif static int mqfs_reclaim(struct vop_reclaim_args *ap) { struct mqfs_info *mqfs = VFSTOMQFS(ap->a_vp->v_mount); struct vnode *vp = ap->a_vp; struct mqfs_node *pn; struct mqfs_vdata *vd; vd = vp->v_data; pn = vd->mv_node; sx_xlock(&mqfs->mi_lock); vp->v_data = NULL; LIST_REMOVE(vd, mv_link); mqnode_release(pn); sx_xunlock(&mqfs->mi_lock); uma_zfree(mvdata_zone, vd); return (0); } #if 0 struct vop_open_args { struct vop_generic_args a_gen; struct vnode *a_vp; int a_mode; struct ucred *a_cred; struct thread *a_td; struct file *a_fp; }; #endif static int mqfs_open(struct vop_open_args *ap) { return (0); } #if 0 struct vop_close_args { struct vop_generic_args a_gen; struct vnode *a_vp; int a_fflag; struct ucred *a_cred; struct thread *a_td; }; #endif static int mqfs_close(struct vop_close_args *ap) { return (0); } #if 0 struct vop_access_args { struct vop_generic_args a_gen; struct vnode *a_vp; accmode_t a_accmode; struct ucred *a_cred; struct thread *a_td; }; #endif /* * Verify permissions */ static int mqfs_access(struct vop_access_args *ap) { struct vnode *vp = ap->a_vp; struct vattr vattr; int error; error = VOP_GETATTR(vp, &vattr, ap->a_cred); if (error) return (error); error = vaccess(vp->v_type, vattr.va_mode, vattr.va_uid, vattr.va_gid, ap->a_accmode, ap->a_cred); return (error); } #if 0 struct vop_getattr_args { struct vop_generic_args a_gen; struct vnode *a_vp; struct vattr *a_vap; struct ucred *a_cred; }; #endif /* * Get file attributes */ static int mqfs_getattr(struct vop_getattr_args *ap) { struct vnode *vp = ap->a_vp; struct mqfs_node *pn = VTON(vp); struct vattr *vap = ap->a_vap; int error = 0; vap->va_type = vp->v_type; vap->va_mode = pn->mn_mode; vap->va_nlink = 1; vap->va_uid = pn->mn_uid; vap->va_gid = pn->mn_gid; vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; vap->va_fileid = pn->mn_fileno; vap->va_size = 0; vap->va_blocksize = PAGE_SIZE; vap->va_bytes = vap->va_size = 0; vap->va_atime = pn->mn_atime; vap->va_mtime = pn->mn_mtime; vap->va_ctime = pn->mn_ctime; vap->va_birthtime = pn->mn_birth; vap->va_gen = 0; vap->va_flags = 0; vap->va_rdev = NODEV; vap->va_bytes = 0; vap->va_filerev = 0; return (error); } #if 0 struct vop_setattr_args { struct vop_generic_args a_gen; struct vnode *a_vp; struct vattr *a_vap; struct ucred *a_cred; }; #endif /* * Set attributes */ static int mqfs_setattr(struct vop_setattr_args *ap) { struct mqfs_node *pn; struct vattr *vap; struct vnode *vp; struct thread *td; int c, error; uid_t uid; gid_t gid; td = curthread; vap = ap->a_vap; vp = ap->a_vp; if (vap->va_type != VNON || vap->va_nlink != VNOVAL || vap->va_fsid != VNOVAL || vap->va_fileid != VNOVAL || vap->va_blocksize != VNOVAL || (vap->va_flags != VNOVAL && vap->va_flags != 0) || vap->va_rdev != VNOVAL || (int)vap->va_bytes != VNOVAL || vap->va_gen != VNOVAL) { return (EINVAL); } pn = VTON(vp); error = c = 0; if (vap->va_uid == (uid_t)VNOVAL) uid = pn->mn_uid; else uid = vap->va_uid; if (vap->va_gid == (gid_t)VNOVAL) gid = pn->mn_gid; else gid = vap->va_gid; if (uid != pn->mn_uid || gid != pn->mn_gid) { /* * To modify the ownership of a file, must possess VADMIN * for that file. */ if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td))) return (error); /* * XXXRW: Why is there a privilege check here: shouldn't the * check in VOP_ACCESS() be enough? Also, are the group bits * below definitely right? */ if ((ap->a_cred->cr_uid != pn->mn_uid || uid != pn->mn_uid || (gid != pn->mn_gid && !groupmember(gid, ap->a_cred))) && (error = priv_check(td, PRIV_MQ_ADMIN)) != 0) return (error); pn->mn_uid = uid; pn->mn_gid = gid; c = 1; } if (vap->va_mode != (mode_t)VNOVAL) { if (ap->a_cred->cr_uid != pn->mn_uid && (error = priv_check(td, PRIV_MQ_ADMIN))) return (error); pn->mn_mode = vap->va_mode; c = 1; } if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { /* See the comment in ufs_vnops::ufs_setattr(). */ if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td)) && ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td)))) return (error); if (vap->va_atime.tv_sec != VNOVAL) { pn->mn_atime = vap->va_atime; } if (vap->va_mtime.tv_sec != VNOVAL) { pn->mn_mtime = vap->va_mtime; } c = 1; } if (c) { vfs_timestamp(&pn->mn_ctime); } return (0); } #if 0 struct vop_read_args { struct vop_generic_args a_gen; struct vnode *a_vp; struct uio *a_uio; int a_ioflag; struct ucred *a_cred; }; #endif /* * Read from a file */ static int mqfs_read(struct vop_read_args *ap) { char buf[80]; struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct mqueue *mq; int len, error; if (vp->v_type != VREG) return (EINVAL); mq = VTOMQ(vp); snprintf(buf, sizeof(buf), "QSIZE:%-10ld MAXMSG:%-10ld CURMSG:%-10ld MSGSIZE:%-10ld\n", mq->mq_totalbytes, mq->mq_maxmsg, mq->mq_curmsgs, mq->mq_msgsize); buf[sizeof(buf)-1] = '\0'; len = strlen(buf); error = uiomove_frombuf(buf, len, uio); return (error); } #if 0 struct vop_readdir_args { struct vop_generic_args a_gen; struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; int *a_eofflag; int *a_ncookies; uint64_t **a_cookies; }; #endif /* * Return directory entries. */ static int mqfs_readdir(struct vop_readdir_args *ap) { struct vnode *vp; struct mqfs_info *mi; struct mqfs_node *pd; struct mqfs_node *pn; struct dirent entry; struct uio *uio; const void *pr_root; int *tmp_ncookies = NULL; off_t offset; int error, i; vp = ap->a_vp; mi = VFSTOMQFS(vp->v_mount); pd = VTON(vp); uio = ap->a_uio; if (vp->v_type != VDIR) return (ENOTDIR); if (uio->uio_offset < 0) return (EINVAL); if (ap->a_ncookies != NULL) { tmp_ncookies = ap->a_ncookies; *ap->a_ncookies = 0; ap->a_ncookies = NULL; } error = 0; offset = 0; pr_root = ap->a_cred->cr_prison->pr_root; sx_xlock(&mi->mi_lock); LIST_FOREACH(pn, &pd->mn_children, mn_sibling) { entry.d_reclen = sizeof(entry); /* * Only show names within the same prison root directory * (or not associated with a prison, e.g. "." and ".."). */ if (pn->mn_pr_root != NULL && pn->mn_pr_root != pr_root) continue; if (!pn->mn_fileno) mqfs_fileno_alloc(mi, pn); entry.d_fileno = pn->mn_fileno; entry.d_off = offset + entry.d_reclen; for (i = 0; i < MQFS_NAMELEN - 1 && pn->mn_name[i] != '\0'; ++i) entry.d_name[i] = pn->mn_name[i]; entry.d_namlen = i; switch (pn->mn_type) { case mqfstype_root: case mqfstype_dir: case mqfstype_this: case mqfstype_parent: entry.d_type = DT_DIR; break; case mqfstype_file: entry.d_type = DT_REG; break; case mqfstype_symlink: entry.d_type = DT_LNK; break; default: panic("%s has unexpected node type: %d", pn->mn_name, pn->mn_type); } dirent_terminate(&entry); if (entry.d_reclen > uio->uio_resid) break; if (offset >= uio->uio_offset) { error = vfs_read_dirent(ap, &entry, offset); if (error) break; } offset += entry.d_reclen; } sx_xunlock(&mi->mi_lock); uio->uio_offset = offset; if (tmp_ncookies != NULL) ap->a_ncookies = tmp_ncookies; return (error); } #ifdef notyet #if 0 struct vop_mkdir_args { struct vnode *a_dvp; struvt vnode **a_vpp; struvt componentname *a_cnp; struct vattr *a_vap; }; #endif /* * Create a directory. */ static int mqfs_mkdir(struct vop_mkdir_args *ap) { struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); struct componentname *cnp = ap->a_cnp; struct mqfs_node *pd = VTON(ap->a_dvp); struct mqfs_node *pn; int error; if (pd->mn_type != mqfstype_root && pd->mn_type != mqfstype_dir) return (ENOTDIR); sx_xlock(&mqfs->mi_lock); pn = mqfs_create_dir(pd, cnp->cn_nameptr, cnp->cn_namelen, ap->a_vap->cn_cred, ap->a_vap->va_mode); if (pn != NULL) mqnode_addref(pn); sx_xunlock(&mqfs->mi_lock); if (pn == NULL) { error = ENOSPC; } else { error = mqfs_allocv(ap->a_dvp->v_mount, ap->a_vpp, pn); mqnode_release(pn); } return (error); } #if 0 struct vop_rmdir_args { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; }; #endif /* * Remove a directory. */ static int mqfs_rmdir(struct vop_rmdir_args *ap) { struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); struct mqfs_node *pn = VTON(ap->a_vp); struct mqfs_node *pt; if (pn->mn_type != mqfstype_dir) return (ENOTDIR); sx_xlock(&mqfs->mi_lock); if (pn->mn_deleted) { sx_xunlock(&mqfs->mi_lock); return (ENOENT); } pt = LIST_FIRST(&pn->mn_children); pt = LIST_NEXT(pt, mn_sibling); pt = LIST_NEXT(pt, mn_sibling); if (pt != NULL) { sx_xunlock(&mqfs->mi_lock); return (ENOTEMPTY); } pt = pn->mn_parent; pn->mn_parent = NULL; pn->mn_deleted = 1; LIST_REMOVE(pn, mn_sibling); mqnode_release(pn); mqnode_release(pt); sx_xunlock(&mqfs->mi_lock); cache_purge(ap->a_vp); return (0); } #endif /* notyet */ /* * See if this prison root is obsolete, and clean up associated queues if it is. */ static int mqfs_prison_remove(void *obj, void *data __unused) { const struct prison *pr = obj; struct prison *tpr; struct mqfs_node *pn, *tpn; struct vnode *pr_root; pr_root = pr->pr_root; if (pr->pr_parent->pr_root == pr_root) return (0); TAILQ_FOREACH(tpr, &allprison, pr_list) { if (tpr != pr && tpr->pr_root == pr_root) return (0); } /* * No jails are rooted in this directory anymore, * so no queues should be either. */ sx_xlock(&mqfs_data.mi_lock); LIST_FOREACH_SAFE(pn, &mqfs_data.mi_root->mn_children, mn_sibling, tpn) { if (pn->mn_pr_root == pr_root) (void)do_unlink(pn, curthread->td_ucred); } sx_xunlock(&mqfs_data.mi_lock); return (0); } /* * Allocate a message queue */ static struct mqueue * mqueue_alloc(const struct mq_attr *attr) { struct mqueue *mq; if (curmq >= maxmq) return (NULL); mq = uma_zalloc(mqueue_zone, M_WAITOK | M_ZERO); TAILQ_INIT(&mq->mq_msgq); if (attr != NULL) { mq->mq_maxmsg = attr->mq_maxmsg; mq->mq_msgsize = attr->mq_msgsize; } else { mq->mq_maxmsg = default_maxmsg; mq->mq_msgsize = default_msgsize; } mtx_init(&mq->mq_mutex, "mqueue lock", NULL, MTX_DEF); knlist_init_mtx(&mq->mq_rsel.si_note, &mq->mq_mutex); knlist_init_mtx(&mq->mq_wsel.si_note, &mq->mq_mutex); atomic_add_int(&curmq, 1); return (mq); } /* * Destroy a message queue */ static void mqueue_free(struct mqueue *mq) { struct mqueue_msg *msg; while ((msg = TAILQ_FIRST(&mq->mq_msgq)) != NULL) { TAILQ_REMOVE(&mq->mq_msgq, msg, msg_link); free(msg, M_MQUEUEDATA); } mtx_destroy(&mq->mq_mutex); seldrain(&mq->mq_rsel); seldrain(&mq->mq_wsel); knlist_destroy(&mq->mq_rsel.si_note); knlist_destroy(&mq->mq_wsel.si_note); uma_zfree(mqueue_zone, mq); atomic_add_int(&curmq, -1); } /* * Load a message from user space */ static struct mqueue_msg * mqueue_loadmsg(const char *msg_ptr, size_t msg_size, int msg_prio) { struct mqueue_msg *msg; size_t len; int error; len = sizeof(struct mqueue_msg) + msg_size; msg = malloc(len, M_MQUEUEDATA, M_WAITOK); error = copyin(msg_ptr, ((char *)msg) + sizeof(struct mqueue_msg), msg_size); if (error) { free(msg, M_MQUEUEDATA); msg = NULL; } else { msg->msg_size = msg_size; msg->msg_prio = msg_prio; } return (msg); } /* * Save a message to user space */ static int mqueue_savemsg(struct mqueue_msg *msg, char *msg_ptr, int *msg_prio) { int error; error = copyout(((char *)msg) + sizeof(*msg), msg_ptr, msg->msg_size); if (error == 0 && msg_prio != NULL) error = copyout(&msg->msg_prio, msg_prio, sizeof(int)); return (error); } /* * Free a message's memory */ static __inline void mqueue_freemsg(struct mqueue_msg *msg) { free(msg, M_MQUEUEDATA); } /* * Send a message. if waitok is false, thread will not be * blocked if there is no data in queue, otherwise, absolute * time will be checked. */ int mqueue_send(struct mqueue *mq, const char *msg_ptr, size_t msg_len, unsigned msg_prio, int waitok, const struct timespec *abs_timeout) { struct mqueue_msg *msg; struct timespec ts, ts2; struct timeval tv; int error; if (msg_prio >= MQ_PRIO_MAX) return (EINVAL); if (msg_len > mq->mq_msgsize) return (EMSGSIZE); msg = mqueue_loadmsg(msg_ptr, msg_len, msg_prio); if (msg == NULL) return (EFAULT); /* O_NONBLOCK case */ if (!waitok) { error = _mqueue_send(mq, msg, -1); if (error) goto bad; return (0); } /* we allow a null timeout (wait forever) */ if (abs_timeout == NULL) { error = _mqueue_send(mq, msg, 0); if (error) goto bad; return (0); } /* send it before checking time */ error = _mqueue_send(mq, msg, -1); if (error == 0) return (0); if (error != EAGAIN) goto bad; if (abs_timeout->tv_nsec >= 1000000000 || abs_timeout->tv_nsec < 0) { error = EINVAL; goto bad; } for (;;) { getnanotime(&ts); timespecsub(abs_timeout, &ts, &ts2); if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { error = ETIMEDOUT; break; } TIMESPEC_TO_TIMEVAL(&tv, &ts2); error = _mqueue_send(mq, msg, tvtohz(&tv)); if (error != ETIMEDOUT) break; } if (error == 0) return (0); bad: mqueue_freemsg(msg); return (error); } /* * Common routine to send a message */ static int _mqueue_send(struct mqueue *mq, struct mqueue_msg *msg, int timo) { struct mqueue_msg *msg2; int error = 0; mtx_lock(&mq->mq_mutex); while (mq->mq_curmsgs >= mq->mq_maxmsg && error == 0) { if (timo < 0) { mtx_unlock(&mq->mq_mutex); return (EAGAIN); } mq->mq_senders++; error = msleep(&mq->mq_senders, &mq->mq_mutex, PCATCH, "mqsend", timo); mq->mq_senders--; if (error == EAGAIN) error = ETIMEDOUT; } if (mq->mq_curmsgs >= mq->mq_maxmsg) { mtx_unlock(&mq->mq_mutex); return (error); } error = 0; if (TAILQ_EMPTY(&mq->mq_msgq)) { TAILQ_INSERT_HEAD(&mq->mq_msgq, msg, msg_link); } else { if (msg->msg_prio <= TAILQ_LAST(&mq->mq_msgq, msgq)->msg_prio) { TAILQ_INSERT_TAIL(&mq->mq_msgq, msg, msg_link); } else { TAILQ_FOREACH(msg2, &mq->mq_msgq, msg_link) { if (msg2->msg_prio < msg->msg_prio) break; } TAILQ_INSERT_BEFORE(msg2, msg, msg_link); } } mq->mq_curmsgs++; mq->mq_totalbytes += msg->msg_size; if (mq->mq_receivers) wakeup_one(&mq->mq_receivers); else if (mq->mq_notifier != NULL) mqueue_send_notification(mq); if (mq->mq_flags & MQ_RSEL) { mq->mq_flags &= ~MQ_RSEL; selwakeup(&mq->mq_rsel); } KNOTE_LOCKED(&mq->mq_rsel.si_note, 0); mtx_unlock(&mq->mq_mutex); return (0); } /* * Send realtime a signal to process which registered itself * successfully by mq_notify. */ static void mqueue_send_notification(struct mqueue *mq) { struct mqueue_notifier *nt; struct thread *td; struct proc *p; int error; mtx_assert(&mq->mq_mutex, MA_OWNED); nt = mq->mq_notifier; if (nt->nt_sigev.sigev_notify != SIGEV_NONE) { p = nt->nt_proc; error = sigev_findtd(p, &nt->nt_sigev, &td); if (error) { mq->mq_notifier = NULL; return; } if (!KSI_ONQ(&nt->nt_ksi)) { ksiginfo_set_sigev(&nt->nt_ksi, &nt->nt_sigev); tdsendsignal(p, td, nt->nt_ksi.ksi_signo, &nt->nt_ksi); } PROC_UNLOCK(p); } mq->mq_notifier = NULL; } /* * Get a message. if waitok is false, thread will not be * blocked if there is no data in queue, otherwise, absolute * time will be checked. */ int mqueue_receive(struct mqueue *mq, char *msg_ptr, size_t msg_len, unsigned *msg_prio, int waitok, const struct timespec *abs_timeout) { struct mqueue_msg *msg; struct timespec ts, ts2; struct timeval tv; int error; if (msg_len < mq->mq_msgsize) return (EMSGSIZE); /* O_NONBLOCK case */ if (!waitok) { error = _mqueue_recv(mq, &msg, -1); if (error) return (error); goto received; } /* we allow a null timeout (wait forever). */ if (abs_timeout == NULL) { error = _mqueue_recv(mq, &msg, 0); if (error) return (error); goto received; } /* try to get a message before checking time */ error = _mqueue_recv(mq, &msg, -1); if (error == 0) goto received; if (error != EAGAIN) return (error); if (abs_timeout->tv_nsec >= 1000000000 || abs_timeout->tv_nsec < 0) { error = EINVAL; return (error); } for (;;) { getnanotime(&ts); timespecsub(abs_timeout, &ts, &ts2); if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { error = ETIMEDOUT; return (error); } TIMESPEC_TO_TIMEVAL(&tv, &ts2); error = _mqueue_recv(mq, &msg, tvtohz(&tv)); if (error == 0) break; if (error != ETIMEDOUT) return (error); } received: error = mqueue_savemsg(msg, msg_ptr, msg_prio); if (error == 0) { curthread->td_retval[0] = msg->msg_size; curthread->td_retval[1] = 0; } mqueue_freemsg(msg); return (error); } /* * Common routine to receive a message */ static int _mqueue_recv(struct mqueue *mq, struct mqueue_msg **msg, int timo) { int error = 0; mtx_lock(&mq->mq_mutex); while ((*msg = TAILQ_FIRST(&mq->mq_msgq)) == NULL && error == 0) { if (timo < 0) { mtx_unlock(&mq->mq_mutex); return (EAGAIN); } mq->mq_receivers++; error = msleep(&mq->mq_receivers, &mq->mq_mutex, PCATCH, "mqrecv", timo); mq->mq_receivers--; if (error == EAGAIN) error = ETIMEDOUT; } if (*msg != NULL) { error = 0; TAILQ_REMOVE(&mq->mq_msgq, *msg, msg_link); mq->mq_curmsgs--; mq->mq_totalbytes -= (*msg)->msg_size; if (mq->mq_senders) wakeup_one(&mq->mq_senders); if (mq->mq_flags & MQ_WSEL) { mq->mq_flags &= ~MQ_WSEL; selwakeup(&mq->mq_wsel); } KNOTE_LOCKED(&mq->mq_wsel.si_note, 0); } if (mq->mq_notifier != NULL && mq->mq_receivers == 0 && !TAILQ_EMPTY(&mq->mq_msgq)) { mqueue_send_notification(mq); } mtx_unlock(&mq->mq_mutex); return (error); } static __inline struct mqueue_notifier * notifier_alloc(void) { return (uma_zalloc(mqnoti_zone, M_WAITOK | M_ZERO)); } static __inline void notifier_free(struct mqueue_notifier *p) { uma_zfree(mqnoti_zone, p); } static struct mqueue_notifier * notifier_search(struct proc *p, int fd) { struct mqueue_notifier *nt; LIST_FOREACH(nt, &p->p_mqnotifier, nt_link) { if (nt->nt_ksi.ksi_mqd == fd) break; } return (nt); } static __inline void notifier_insert(struct proc *p, struct mqueue_notifier *nt) { LIST_INSERT_HEAD(&p->p_mqnotifier, nt, nt_link); } static __inline void notifier_delete(struct proc *p, struct mqueue_notifier *nt) { LIST_REMOVE(nt, nt_link); notifier_free(nt); } static void notifier_remove(struct proc *p, struct mqueue *mq, int fd) { struct mqueue_notifier *nt; mtx_assert(&mq->mq_mutex, MA_OWNED); PROC_LOCK(p); nt = notifier_search(p, fd); if (nt != NULL) { if (mq->mq_notifier == nt) mq->mq_notifier = NULL; sigqueue_take(&nt->nt_ksi); notifier_delete(p, nt); } PROC_UNLOCK(p); } int kern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode, const struct mq_attr *attr) { char *path, pathbuf[MQFS_NAMELEN + 1]; struct mqfs_node *pn; struct pwddesc *pdp; struct file *fp; struct mqueue *mq; int fd, error, len, cmode; AUDIT_ARG_FFLAGS(flags); AUDIT_ARG_MODE(mode); pdp = td->td_proc->p_pd; cmode = ((mode & ~pdp->pd_cmask) & ALLPERMS) & ~S_ISTXT; mq = NULL; if ((flags & O_CREAT) != 0 && attr != NULL) { if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > maxmsg) return (EINVAL); if (attr->mq_msgsize <= 0 || attr->mq_msgsize > maxmsgsize) return (EINVAL); } path = pathbuf; error = copyinstr(upath, path, MQFS_NAMELEN + 1, NULL); if (error) return (error); /* * The first character of name may be a slash (/) character * and the remaining characters of name cannot include any slash * characters. */ len = strlen(path); if (len < 2 || strchr(path + 1, '/') != NULL) return (EINVAL); if (path[0] == '/') { path++; len--; } /* * "." and ".." are magic directories, populated on the fly, and cannot * be opened as queues. */ if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) return (EINVAL); AUDIT_ARG_UPATH1_CANON(pathbuf); error = falloc(td, &fp, &fd, O_CLOEXEC); if (error) return (error); sx_xlock(&mqfs_data.mi_lock); pn = mqfs_search(mqfs_data.mi_root, path, len, td->td_ucred); if (pn == NULL) { if (!(flags & O_CREAT)) { error = ENOENT; } else { mq = mqueue_alloc(attr); if (mq == NULL) { error = ENFILE; } else { pn = mqfs_create_file(mqfs_data.mi_root, path, len, td->td_ucred, cmode); if (pn == NULL) { error = ENOSPC; mqueue_free(mq); } } } if (error == 0) { pn->mn_data = mq; } } else { if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { error = EEXIST; } else { accmode_t accmode = 0; if (flags & FREAD) accmode |= VREAD; if (flags & FWRITE) accmode |= VWRITE; error = vaccess(VREG, pn->mn_mode, pn->mn_uid, pn->mn_gid, accmode, td->td_ucred); } } if (error) { sx_xunlock(&mqfs_data.mi_lock); fdclose(td, fp, fd); fdrop(fp, td); return (error); } mqnode_addref(pn); sx_xunlock(&mqfs_data.mi_lock); finit(fp, flags & (FREAD | FWRITE | O_NONBLOCK), DTYPE_MQUEUE, pn, &mqueueops); td->td_retval[0] = fd; fdrop(fp, td); return (0); } /* * Syscall to open a message queue. */ int sys_kmq_open(struct thread *td, struct kmq_open_args *uap) { struct mq_attr attr; int flags, error; if ((uap->flags & O_ACCMODE) == O_ACCMODE || uap->flags & O_EXEC) return (EINVAL); flags = FFLAGS(uap->flags); if ((flags & O_CREAT) != 0 && uap->attr != NULL) { error = copyin(uap->attr, &attr, sizeof(attr)); if (error) return (error); } return (kern_kmq_open(td, uap->path, flags, uap->mode, uap->attr != NULL ? &attr : NULL)); } /* * Syscall to unlink a message queue. */ int sys_kmq_unlink(struct thread *td, struct kmq_unlink_args *uap) { char *path, pathbuf[MQFS_NAMELEN + 1]; struct mqfs_node *pn; int error, len; path = pathbuf; error = copyinstr(uap->path, path, MQFS_NAMELEN + 1, NULL); if (error) return (error); len = strlen(path); if (len < 2 || strchr(path + 1, '/') != NULL) return (EINVAL); if (path[0] == '/') { path++; len--; } if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) return (EINVAL); AUDIT_ARG_UPATH1_CANON(pathbuf); sx_xlock(&mqfs_data.mi_lock); pn = mqfs_search(mqfs_data.mi_root, path, len, td->td_ucred); if (pn != NULL) error = do_unlink(pn, td->td_ucred); else error = ENOENT; sx_xunlock(&mqfs_data.mi_lock); return (error); } typedef int (*_fgetf)(struct thread *, int, const cap_rights_t *, struct file **); /* * Get message queue by giving file slot */ static int _getmq(struct thread *td, int fd, const cap_rights_t *rightsp, _fgetf func, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { struct mqfs_node *pn; int error; error = func(td, fd, rightsp, fpp); if (error) return (error); if (&mqueueops != (*fpp)->f_ops) { fdrop(*fpp, td); return (EBADF); } pn = (*fpp)->f_data; if (ppn) *ppn = pn; if (pmq) *pmq = pn->mn_data; return (0); } static __inline int getmq(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { return _getmq(td, fd, &cap_event_rights, fget, fpp, ppn, pmq); } static __inline int getmq_read(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { return _getmq(td, fd, &cap_read_rights, fget_read, fpp, ppn, pmq); } static __inline int getmq_write(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { return _getmq(td, fd, &cap_write_rights, fget_write, fpp, ppn, pmq); } int kern_kmq_setattr(struct thread *td, int mqd, const struct mq_attr *attr, struct mq_attr *oattr) { struct mqueue *mq; struct file *fp; u_int oflag, flag; int error; AUDIT_ARG_FD(mqd); if (attr != NULL && (attr->mq_flags & ~O_NONBLOCK) != 0) return (EINVAL); error = getmq(td, mqd, &fp, NULL, &mq); if (error) return (error); oattr->mq_maxmsg = mq->mq_maxmsg; oattr->mq_msgsize = mq->mq_msgsize; oattr->mq_curmsgs = mq->mq_curmsgs; if (attr != NULL) { do { oflag = flag = fp->f_flag; flag &= ~O_NONBLOCK; flag |= (attr->mq_flags & O_NONBLOCK); } while (atomic_cmpset_int(&fp->f_flag, oflag, flag) == 0); } else oflag = fp->f_flag; oattr->mq_flags = (O_NONBLOCK & oflag); fdrop(fp, td); return (error); } int sys_kmq_setattr(struct thread *td, struct kmq_setattr_args *uap) { struct mq_attr attr, oattr; int error; if (uap->attr != NULL) { error = copyin(uap->attr, &attr, sizeof(attr)); if (error != 0) return (error); } error = kern_kmq_setattr(td, uap->mqd, uap->attr != NULL ? &attr : NULL, &oattr); if (error == 0 && uap->oattr != NULL) { bzero(oattr.__reserved, sizeof(oattr.__reserved)); error = copyout(&oattr, uap->oattr, sizeof(oattr)); } return (error); } int kern_kmq_timedreceive(struct thread *td, int mqd, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout) { struct mqueue *mq; struct file *fp; int error, waitok; AUDIT_ARG_FD(mqd); error = getmq_read(td, mqd, &fp, NULL, &mq); if (error != 0) return (error); waitok = (fp->f_flag & O_NONBLOCK) == 0; error = mqueue_receive(mq, msg_ptr, msg_len, msg_prio, waitok, abs_timeout); fdrop(fp, td); return (error); } int sys_kmq_timedreceive(struct thread *td, struct kmq_timedreceive_args *uap) { struct timespec *abs_timeout, ets; int error; if (uap->abs_timeout != NULL) { error = copyin(uap->abs_timeout, &ets, sizeof(ets)); if (error != 0) return (error); abs_timeout = &ets; } else abs_timeout = NULL; return (kern_kmq_timedreceive(td, uap->mqd, uap->msg_ptr, uap->msg_len, uap->msg_prio, abs_timeout)); } int kern_kmq_timedsend(struct thread *td, int mqd, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout) { struct mqueue *mq; struct file *fp; int error, waitok; AUDIT_ARG_FD(mqd); error = getmq_write(td, mqd, &fp, NULL, &mq); if (error != 0) return (error); waitok = (fp->f_flag & O_NONBLOCK) == 0; error = mqueue_send(mq, msg_ptr, msg_len, msg_prio, waitok, abs_timeout); fdrop(fp, td); return (error); } int sys_kmq_timedsend(struct thread *td, struct kmq_timedsend_args *uap) { struct timespec *abs_timeout, ets; int error; if (uap->abs_timeout != NULL) { error = copyin(uap->abs_timeout, &ets, sizeof(ets)); if (error != 0) return (error); abs_timeout = &ets; } else abs_timeout = NULL; return (kern_kmq_timedsend(td, uap->mqd, uap->msg_ptr, uap->msg_len, uap->msg_prio, abs_timeout)); } int kern_kmq_notify(struct thread *td, int mqd, struct sigevent *sigev) { struct filedesc *fdp; struct proc *p; struct mqueue *mq; struct file *fp, *fp2; struct mqueue_notifier *nt, *newnt = NULL; int error; AUDIT_ARG_FD(mqd); if (sigev != NULL) { if (sigev->sigev_notify != SIGEV_SIGNAL && sigev->sigev_notify != SIGEV_THREAD_ID && sigev->sigev_notify != SIGEV_NONE) return (EINVAL); if ((sigev->sigev_notify == SIGEV_SIGNAL || sigev->sigev_notify == SIGEV_THREAD_ID) && !_SIG_VALID(sigev->sigev_signo)) return (EINVAL); } p = td->td_proc; fdp = td->td_proc->p_fd; error = getmq(td, mqd, &fp, NULL, &mq); if (error) return (error); again: FILEDESC_SLOCK(fdp); fp2 = fget_noref(fdp, mqd); if (fp2 == NULL) { FILEDESC_SUNLOCK(fdp); error = EBADF; goto out; } #ifdef CAPABILITIES error = cap_check(cap_rights(fdp, mqd), &cap_event_rights); if (error) { FILEDESC_SUNLOCK(fdp); goto out; } #endif if (fp2 != fp) { FILEDESC_SUNLOCK(fdp); error = EBADF; goto out; } mtx_lock(&mq->mq_mutex); FILEDESC_SUNLOCK(fdp); if (sigev != NULL) { if (mq->mq_notifier != NULL) { error = EBUSY; } else { PROC_LOCK(p); nt = notifier_search(p, mqd); if (nt == NULL) { if (newnt == NULL) { PROC_UNLOCK(p); mtx_unlock(&mq->mq_mutex); newnt = notifier_alloc(); goto again; } } if (nt != NULL) { sigqueue_take(&nt->nt_ksi); if (newnt != NULL) { notifier_free(newnt); newnt = NULL; } } else { nt = newnt; newnt = NULL; ksiginfo_init(&nt->nt_ksi); nt->nt_ksi.ksi_flags |= KSI_INS | KSI_EXT; nt->nt_ksi.ksi_code = SI_MESGQ; nt->nt_proc = p; nt->nt_ksi.ksi_mqd = mqd; notifier_insert(p, nt); } nt->nt_sigev = *sigev; mq->mq_notifier = nt; PROC_UNLOCK(p); /* * if there is no receivers and message queue * is not empty, we should send notification * as soon as possible. */ if (mq->mq_receivers == 0 && !TAILQ_EMPTY(&mq->mq_msgq)) mqueue_send_notification(mq); } } else { notifier_remove(p, mq, mqd); } mtx_unlock(&mq->mq_mutex); out: fdrop(fp, td); if (newnt != NULL) notifier_free(newnt); return (error); } int sys_kmq_notify(struct thread *td, struct kmq_notify_args *uap) { struct sigevent ev, *evp; int error; if (uap->sigev == NULL) { evp = NULL; } else { error = copyin(uap->sigev, &ev, sizeof(ev)); if (error != 0) return (error); evp = &ev; } return (kern_kmq_notify(td, uap->mqd, evp)); } static void mqueue_fdclose(struct thread *td, int fd, struct file *fp) { struct mqueue *mq; #ifdef INVARIANTS struct filedesc *fdp; fdp = td->td_proc->p_fd; FILEDESC_LOCK_ASSERT(fdp); #endif if (fp->f_ops == &mqueueops) { mq = FPTOMQ(fp); mtx_lock(&mq->mq_mutex); notifier_remove(td->td_proc, mq, fd); /* have to wakeup thread in same process */ if (mq->mq_flags & MQ_RSEL) { mq->mq_flags &= ~MQ_RSEL; selwakeup(&mq->mq_rsel); } if (mq->mq_flags & MQ_WSEL) { mq->mq_flags &= ~MQ_WSEL; selwakeup(&mq->mq_wsel); } mtx_unlock(&mq->mq_mutex); } } static void mq_proc_exit(void *arg __unused, struct proc *p) { struct filedesc *fdp; struct file *fp; struct mqueue *mq; int i; fdp = p->p_fd; FILEDESC_SLOCK(fdp); for (i = 0; i < fdp->fd_nfiles; ++i) { fp = fget_noref(fdp, i); if (fp != NULL && fp->f_ops == &mqueueops) { mq = FPTOMQ(fp); mtx_lock(&mq->mq_mutex); notifier_remove(p, FPTOMQ(fp), i); mtx_unlock(&mq->mq_mutex); } } FILEDESC_SUNLOCK(fdp); KASSERT(LIST_EMPTY(&p->p_mqnotifier), ("mq notifiers left")); } static int mqf_poll(struct file *fp, int events, struct ucred *active_cred, struct thread *td) { struct mqueue *mq = FPTOMQ(fp); int revents = 0; mtx_lock(&mq->mq_mutex); if (events & (POLLIN | POLLRDNORM)) { if (mq->mq_curmsgs) { revents |= events & (POLLIN | POLLRDNORM); } else { mq->mq_flags |= MQ_RSEL; selrecord(td, &mq->mq_rsel); } } if (events & POLLOUT) { if (mq->mq_curmsgs < mq->mq_maxmsg) revents |= POLLOUT; else { mq->mq_flags |= MQ_WSEL; selrecord(td, &mq->mq_wsel); } } mtx_unlock(&mq->mq_mutex); return (revents); } static int mqf_close(struct file *fp, struct thread *td) { struct mqfs_node *pn; fp->f_ops = &badfileops; pn = fp->f_data; fp->f_data = NULL; sx_xlock(&mqfs_data.mi_lock); mqnode_release(pn); sx_xunlock(&mqfs_data.mi_lock); return (0); } static int mqf_stat(struct file *fp, struct stat *st, struct ucred *active_cred) { struct mqfs_node *pn = fp->f_data; bzero(st, sizeof *st); sx_xlock(&mqfs_data.mi_lock); st->st_atim = pn->mn_atime; st->st_mtim = pn->mn_mtime; st->st_ctim = pn->mn_ctime; st->st_birthtim = pn->mn_birth; st->st_uid = pn->mn_uid; st->st_gid = pn->mn_gid; st->st_mode = S_IFIFO | pn->mn_mode; sx_xunlock(&mqfs_data.mi_lock); return (0); } static int mqf_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, struct thread *td) { struct mqfs_node *pn; int error; error = 0; pn = fp->f_data; sx_xlock(&mqfs_data.mi_lock); error = vaccess(VREG, pn->mn_mode, pn->mn_uid, pn->mn_gid, VADMIN, active_cred); if (error != 0) goto out; pn->mn_mode = mode & ACCESSPERMS; out: sx_xunlock(&mqfs_data.mi_lock); return (error); } static int mqf_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, struct thread *td) { struct mqfs_node *pn; int error; error = 0; pn = fp->f_data; sx_xlock(&mqfs_data.mi_lock); if (uid == (uid_t)-1) uid = pn->mn_uid; if (gid == (gid_t)-1) gid = pn->mn_gid; if (((uid != pn->mn_uid && uid != active_cred->cr_uid) || (gid != pn->mn_gid && !groupmember(gid, active_cred))) && (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN))) goto out; pn->mn_uid = uid; pn->mn_gid = gid; out: sx_xunlock(&mqfs_data.mi_lock); return (error); } static int mqf_kqfilter(struct file *fp, struct knote *kn) { struct mqueue *mq = FPTOMQ(fp); int error = 0; if (kn->kn_filter == EVFILT_READ) { kn->kn_fop = &mq_rfiltops; knlist_add(&mq->mq_rsel.si_note, kn, 0); } else if (kn->kn_filter == EVFILT_WRITE) { kn->kn_fop = &mq_wfiltops; knlist_add(&mq->mq_wsel.si_note, kn, 0); } else error = EINVAL; return (error); } static void filt_mqdetach(struct knote *kn) { struct mqueue *mq = FPTOMQ(kn->kn_fp); if (kn->kn_filter == EVFILT_READ) knlist_remove(&mq->mq_rsel.si_note, kn, 0); else if (kn->kn_filter == EVFILT_WRITE) knlist_remove(&mq->mq_wsel.si_note, kn, 0); else panic("filt_mqdetach"); } static int filt_mqread(struct knote *kn, long hint) { struct mqueue *mq = FPTOMQ(kn->kn_fp); mtx_assert(&mq->mq_mutex, MA_OWNED); return (mq->mq_curmsgs != 0); } static int filt_mqwrite(struct knote *kn, long hint) { struct mqueue *mq = FPTOMQ(kn->kn_fp); mtx_assert(&mq->mq_mutex, MA_OWNED); return (mq->mq_curmsgs < mq->mq_maxmsg); } static int mqf_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) { kif->kf_type = KF_TYPE_MQUEUE; return (0); } static const struct fileops mqueueops = { .fo_read = invfo_rdwr, .fo_write = invfo_rdwr, .fo_truncate = invfo_truncate, .fo_ioctl = invfo_ioctl, .fo_poll = mqf_poll, .fo_kqfilter = mqf_kqfilter, .fo_stat = mqf_stat, .fo_close = mqf_close, .fo_chmod = mqf_chmod, .fo_chown = mqf_chown, .fo_sendfile = invfo_sendfile, .fo_fill_kinfo = mqf_fill_kinfo, .fo_cmp = file_kcmp_generic, .fo_flags = DFLAG_PASSABLE, }; static struct vop_vector mqfs_vnodeops = { .vop_default = &default_vnodeops, .vop_access = mqfs_access, .vop_cachedlookup = mqfs_lookup, .vop_lookup = vfs_cache_lookup, .vop_reclaim = mqfs_reclaim, .vop_create = mqfs_create, .vop_remove = mqfs_remove, .vop_inactive = mqfs_inactive, .vop_open = mqfs_open, .vop_close = mqfs_close, .vop_getattr = mqfs_getattr, .vop_setattr = mqfs_setattr, .vop_read = mqfs_read, .vop_write = VOP_EOPNOTSUPP, .vop_readdir = mqfs_readdir, .vop_mkdir = VOP_EOPNOTSUPP, .vop_rmdir = VOP_EOPNOTSUPP }; VFS_VOP_VECTOR_REGISTER(mqfs_vnodeops); static struct vfsops mqfs_vfsops = { .vfs_init = mqfs_init, .vfs_uninit = mqfs_uninit, .vfs_mount = mqfs_mount, .vfs_unmount = mqfs_unmount, .vfs_root = mqfs_root, .vfs_statfs = mqfs_statfs, }; static struct vfsconf mqueuefs_vfsconf = { .vfc_version = VFS_VERSION, .vfc_name = "mqueuefs", .vfc_vfsops = &mqfs_vfsops, .vfc_typenum = -1, .vfc_flags = VFCF_SYNTHETIC }; static struct syscall_helper_data mq_syscalls[] = { SYSCALL_INIT_HELPER(kmq_open), SYSCALL_INIT_HELPER_F(kmq_setattr, SYF_CAPENABLED), SYSCALL_INIT_HELPER_F(kmq_timedsend, SYF_CAPENABLED), SYSCALL_INIT_HELPER_F(kmq_timedreceive, SYF_CAPENABLED), SYSCALL_INIT_HELPER_F(kmq_notify, SYF_CAPENABLED), SYSCALL_INIT_HELPER(kmq_unlink), SYSCALL_INIT_LAST }; #ifdef COMPAT_FREEBSD32 #include #include #include #include #include static void mq_attr_from32(const struct mq_attr32 *from, struct mq_attr *to) { to->mq_flags = from->mq_flags; to->mq_maxmsg = from->mq_maxmsg; to->mq_msgsize = from->mq_msgsize; to->mq_curmsgs = from->mq_curmsgs; } static void mq_attr_to32(const struct mq_attr *from, struct mq_attr32 *to) { to->mq_flags = from->mq_flags; to->mq_maxmsg = from->mq_maxmsg; to->mq_msgsize = from->mq_msgsize; to->mq_curmsgs = from->mq_curmsgs; } int freebsd32_kmq_open(struct thread *td, struct freebsd32_kmq_open_args *uap) { struct mq_attr attr; struct mq_attr32 attr32; int flags, error; if ((uap->flags & O_ACCMODE) == O_ACCMODE || uap->flags & O_EXEC) return (EINVAL); flags = FFLAGS(uap->flags); if ((flags & O_CREAT) != 0 && uap->attr != NULL) { error = copyin(uap->attr, &attr32, sizeof(attr32)); if (error) return (error); mq_attr_from32(&attr32, &attr); } return (kern_kmq_open(td, uap->path, flags, uap->mode, uap->attr != NULL ? &attr : NULL)); } int freebsd32_kmq_setattr(struct thread *td, struct freebsd32_kmq_setattr_args *uap) { struct mq_attr attr, oattr; struct mq_attr32 attr32, oattr32; int error; if (uap->attr != NULL) { error = copyin(uap->attr, &attr32, sizeof(attr32)); if (error != 0) return (error); mq_attr_from32(&attr32, &attr); } error = kern_kmq_setattr(td, uap->mqd, uap->attr != NULL ? &attr : NULL, &oattr); if (error == 0 && uap->oattr != NULL) { mq_attr_to32(&oattr, &oattr32); bzero(oattr32.__reserved, sizeof(oattr32.__reserved)); error = copyout(&oattr32, uap->oattr, sizeof(oattr32)); } return (error); } int freebsd32_kmq_timedsend(struct thread *td, struct freebsd32_kmq_timedsend_args *uap) { struct timespec32 ets32; struct timespec *abs_timeout, ets; int error; if (uap->abs_timeout != NULL) { error = copyin(uap->abs_timeout, &ets32, sizeof(ets32)); if (error != 0) return (error); CP(ets32, ets, tv_sec); CP(ets32, ets, tv_nsec); abs_timeout = &ets; } else abs_timeout = NULL; return (kern_kmq_timedsend(td, uap->mqd, uap->msg_ptr, uap->msg_len, uap->msg_prio, abs_timeout)); } int freebsd32_kmq_timedreceive(struct thread *td, struct freebsd32_kmq_timedreceive_args *uap) { struct timespec32 ets32; struct timespec *abs_timeout, ets; int error; if (uap->abs_timeout != NULL) { error = copyin(uap->abs_timeout, &ets32, sizeof(ets32)); if (error != 0) return (error); CP(ets32, ets, tv_sec); CP(ets32, ets, tv_nsec); abs_timeout = &ets; } else abs_timeout = NULL; return (kern_kmq_timedreceive(td, uap->mqd, uap->msg_ptr, uap->msg_len, uap->msg_prio, abs_timeout)); } int freebsd32_kmq_notify(struct thread *td, struct freebsd32_kmq_notify_args *uap) { struct sigevent ev, *evp; struct sigevent32 ev32; int error; if (uap->sigev == NULL) { evp = NULL; } else { error = copyin(uap->sigev, &ev32, sizeof(ev32)); if (error != 0) return (error); error = convert_sigevent32(&ev32, &ev); if (error != 0) return (error); evp = &ev; } return (kern_kmq_notify(td, uap->mqd, evp)); } static struct syscall_helper_data mq32_syscalls[] = { SYSCALL32_INIT_HELPER(freebsd32_kmq_open), SYSCALL32_INIT_HELPER_F(freebsd32_kmq_setattr, SYF_CAPENABLED), SYSCALL32_INIT_HELPER_F(freebsd32_kmq_timedsend, SYF_CAPENABLED), SYSCALL32_INIT_HELPER_F(freebsd32_kmq_timedreceive, SYF_CAPENABLED), SYSCALL32_INIT_HELPER_F(freebsd32_kmq_notify, SYF_CAPENABLED), SYSCALL32_INIT_HELPER_COMPAT(kmq_unlink), SYSCALL_INIT_LAST }; #endif static int mqinit(void) { int error; error = syscall_helper_register(mq_syscalls, SY_THR_STATIC_KLD); if (error != 0) return (error); #ifdef COMPAT_FREEBSD32 error = syscall32_helper_register(mq32_syscalls, SY_THR_STATIC_KLD); if (error != 0) return (error); #endif return (0); } static int mqunload(void) { #ifdef COMPAT_FREEBSD32 syscall32_helper_unregister(mq32_syscalls); #endif syscall_helper_unregister(mq_syscalls); return (0); } static int mq_modload(struct module *module, int cmd, void *arg) { int error = 0; error = vfs_modevent(module, cmd, arg); if (error != 0) return (error); switch (cmd) { case MOD_LOAD: error = mqinit(); if (error != 0) mqunload(); break; case MOD_UNLOAD: error = mqunload(); break; default: break; } return (error); } static moduledata_t mqueuefs_mod = { "mqueuefs", mq_modload, &mqueuefs_vfsconf }; DECLARE_MODULE(mqueuefs, mqueuefs_mod, SI_SUB_VFS, SI_ORDER_MIDDLE); MODULE_VERSION(mqueuefs, 1); diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 85f67731e1cc..05d1120030f3 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -1,1644 +1,1644 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed * to Berkeley by John Heidemann of the UCLA Ficus project. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int vop_nolookup(struct vop_lookup_args *); static int vop_norename(struct vop_rename_args *); static int vop_nostrategy(struct vop_strategy_args *); static int dirent_exists(struct vnode *vp, const char *dirname, struct thread *td); static int vop_stdis_text(struct vop_is_text_args *ap); static int vop_stdunset_text(struct vop_unset_text_args *ap); static int vop_stdadd_writecount(struct vop_add_writecount_args *ap); static int vop_stdcopy_file_range(struct vop_copy_file_range_args *ap); static int vop_stdfdatasync(struct vop_fdatasync_args *ap); static int vop_stdgetpages_async(struct vop_getpages_async_args *ap); static int vop_stdread_pgcache(struct vop_read_pgcache_args *ap); static int vop_stdstat(struct vop_stat_args *ap); static int vop_stdvput_pair(struct vop_vput_pair_args *ap); static int vop_stdgetlowvnode(struct vop_getlowvnode_args *ap); /* * This vnode table stores what we want to do if the filesystem doesn't * implement a particular VOP. * * If there is no specific entry here, we will return EOPNOTSUPP. * * Note that every filesystem has to implement either vop_access * or vop_accessx; failing to do so will result in immediate crash * due to stack overflow, as vop_stdaccess() calls vop_stdaccessx(), * which calls vop_stdaccess() etc. */ struct vop_vector default_vnodeops = { .vop_default = NULL, .vop_bypass = VOP_EOPNOTSUPP, .vop_access = vop_stdaccess, .vop_accessx = vop_stdaccessx, .vop_advise = vop_stdadvise, .vop_advlock = vop_stdadvlock, .vop_advlockasync = vop_stdadvlockasync, .vop_advlockpurge = vop_stdadvlockpurge, .vop_allocate = vop_stdallocate, .vop_deallocate = vop_stddeallocate, .vop_bmap = vop_stdbmap, .vop_close = VOP_NULL, .vop_fsync = VOP_NULL, .vop_stat = vop_stdstat, .vop_fdatasync = vop_stdfdatasync, .vop_getlowvnode = vop_stdgetlowvnode, .vop_getpages = vop_stdgetpages, .vop_getpages_async = vop_stdgetpages_async, .vop_getwritemount = vop_stdgetwritemount, .vop_inactive = VOP_NULL, .vop_need_inactive = vop_stdneed_inactive, .vop_inotify = vop_stdinotify, .vop_inotify_add_watch = vop_stdinotify_add_watch, .vop_ioctl = vop_stdioctl, .vop_kqfilter = vop_stdkqfilter, .vop_islocked = vop_stdislocked, .vop_lock1 = vop_stdlock, .vop_lookup = vop_nolookup, .vop_open = VOP_NULL, .vop_pathconf = VOP_EINVAL, .vop_poll = vop_nopoll, .vop_putpages = vop_stdputpages, .vop_readlink = VOP_EINVAL, .vop_read_pgcache = vop_stdread_pgcache, .vop_rename = vop_norename, .vop_revoke = VOP_PANIC, .vop_strategy = vop_nostrategy, .vop_unlock = vop_stdunlock, .vop_vptocnp = vop_stdvptocnp, .vop_vptofh = vop_stdvptofh, .vop_unp_bind = vop_stdunp_bind, .vop_unp_connect = vop_stdunp_connect, .vop_unp_detach = vop_stdunp_detach, .vop_is_text = vop_stdis_text, .vop_set_text = vop_stdset_text, .vop_unset_text = vop_stdunset_text, .vop_add_writecount = vop_stdadd_writecount, .vop_copy_file_range = vop_stdcopy_file_range, .vop_vput_pair = vop_stdvput_pair, }; VFS_VOP_VECTOR_REGISTER(default_vnodeops); /* * Series of placeholder functions for various error returns for * VOPs. */ int vop_eopnotsupp(struct vop_generic_args *ap) { /* printf("vop_notsupp[%s]\n", ap->a_desc->vdesc_name); */ return (EOPNOTSUPP); } int vop_ebadf(struct vop_generic_args *ap) { return (EBADF); } int vop_enotty(struct vop_generic_args *ap) { return (ENOTTY); } int vop_einval(struct vop_generic_args *ap) { return (EINVAL); } int vop_enoent(struct vop_generic_args *ap) { return (ENOENT); } int vop_eagain(struct vop_generic_args *ap) { return (EAGAIN); } int vop_null(struct vop_generic_args *ap) { return (0); } /* * Helper function to panic on some bad VOPs in some filesystems. */ int vop_panic(struct vop_generic_args *ap) { panic("filesystem goof: vop_panic[%s]", ap->a_desc->vdesc_name); } /* * vop_std and vop_no are default functions for use by * filesystems that need the "default reasonable" implementation for a * particular operation. * * The documentation for the operations they implement exists (if it exists) * in the VOP_(9) manpage (all uppercase). */ /* * Default vop for filesystems that do not support name lookup */ static int vop_nolookup(struct vop_lookup_args *ap) { *ap->a_vpp = NULL; return (ENOTDIR); } /* * vop_norename: * * Handle unlock and reference counting for arguments of vop_rename * for filesystems that do not implement rename operation. */ static int vop_norename(struct vop_rename_args *ap) { vop_rename_fail(ap); return (EOPNOTSUPP); } /* * vop_nostrategy: * * Strategy routine for VFS devices that have none. * * BIO_ERROR and B_INVAL must be cleared prior to calling any strategy * routine. Typically this is done for a BIO_READ strategy call. * Typically B_INVAL is assumed to already be clear prior to a write * and should not be cleared manually unless you just made the buffer * invalid. BIO_ERROR should be cleared either way. */ static int vop_nostrategy (struct vop_strategy_args *ap) { printf("No strategy for buffer at %p\n", ap->a_bp); vn_printf(ap->a_vp, "vnode "); ap->a_bp->b_ioflags |= BIO_ERROR; ap->a_bp->b_error = EOPNOTSUPP; bufdone(ap->a_bp); return (EOPNOTSUPP); } /* * Check if a named file exists in a given directory vnode * * Returns 0 if the file exists, ENOENT if it doesn't, or errors returned by * vn_dir_next_dirent(). */ static int dirent_exists(struct vnode *vp, const char *dirname, struct thread *td) { char *dirbuf; int error, eofflag; size_t dirbuflen, len; off_t off; struct dirent *dp; struct vattr va; ASSERT_VOP_LOCKED(vp, "vnode not locked"); KASSERT(vp->v_type == VDIR, ("vp %p is not a directory", vp)); error = VOP_GETATTR(vp, &va, td->td_ucred); if (error != 0) return (error); dirbuflen = MAX(DEV_BSIZE, GENERIC_MAXDIRSIZ); if (dirbuflen < va.va_blocksize) dirbuflen = va.va_blocksize; dirbuf = malloc(dirbuflen, M_TEMP, M_WAITOK); len = 0; off = 0; eofflag = 0; for (;;) { error = vn_dir_next_dirent(vp, td, dirbuf, dirbuflen, &dp, &len, &off, &eofflag); if (error != 0) goto out; if (len == 0) break; if (dp->d_type != DT_WHT && dp->d_fileno != 0 && strcmp(dp->d_name, dirname) == 0) goto out; } error = ENOENT; out: free(dirbuf, M_TEMP); return (error); } int vop_stdaccess(struct vop_access_args *ap) { KASSERT((ap->a_accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0, ("invalid bit in accmode")); return (VOP_ACCESSX(ap->a_vp, ap->a_accmode, ap->a_cred, ap->a_td)); } int vop_stdaccessx(struct vop_accessx_args *ap) { int error; accmode_t accmode = ap->a_accmode; error = vfs_unixify_accmode(&accmode); if (error != 0) return (error); if (accmode == 0) return (0); return (VOP_ACCESS(ap->a_vp, accmode, ap->a_cred, ap->a_td)); } /* * Advisory record locking support */ int vop_stdadvlock(struct vop_advlock_args *ap) { struct vnode *vp; struct mount *mp; struct vattr vattr; int error; vp = ap->a_vp; /* * Provide atomicity of open(O_CREAT | O_EXCL | O_EXLOCK) for * local filesystems. See vn_open_cred() for reciprocal part. */ mp = vp->v_mount; if (mp != NULL && (mp->mnt_flag & MNT_LOCAL) != 0 && ap->a_op == F_SETLK && (ap->a_flags & F_FIRSTOPEN) == 0) { VI_LOCK(vp); while ((vp->v_iflag & VI_FOPENING) != 0) msleep(vp, VI_MTX(vp), PLOCK, "lockfo", 0); VI_UNLOCK(vp); } if (ap->a_fl->l_whence == SEEK_END) { /* * The NFSv4 server must avoid doing a vn_lock() here, since it * can deadlock the nfsd threads, due to a LOR. Fortunately * the NFSv4 server always uses SEEK_SET and this code is * only required for the SEEK_END case. */ vn_lock(vp, LK_SHARED | LK_RETRY); error = VOP_GETATTR(vp, &vattr, curthread->td_ucred); VOP_UNLOCK(vp); if (error) return (error); } else vattr.va_size = 0; return (lf_advlock(ap, &(vp->v_lockf), vattr.va_size)); } int vop_stdadvlockasync(struct vop_advlockasync_args *ap) { struct vnode *vp; struct vattr vattr; int error; vp = ap->a_vp; if (ap->a_fl->l_whence == SEEK_END) { /* The size argument is only needed for SEEK_END. */ vn_lock(vp, LK_SHARED | LK_RETRY); error = VOP_GETATTR(vp, &vattr, curthread->td_ucred); VOP_UNLOCK(vp); if (error) return (error); } else vattr.va_size = 0; return (lf_advlockasync(ap, &(vp->v_lockf), vattr.va_size)); } int vop_stdadvlockpurge(struct vop_advlockpurge_args *ap) { struct vnode *vp; vp = ap->a_vp; lf_purgelocks(vp, &vp->v_lockf); return (0); } /* * vop_stdpathconf: * * Standard implementation of POSIX pathconf, to get information about limits * for a filesystem. * Override per filesystem for the case where the filesystem has smaller * limits. */ int vop_stdpathconf(struct vop_pathconf_args *ap) { switch (ap->a_name) { case _PC_ASYNC_IO: *ap->a_retval = _POSIX_ASYNCHRONOUS_IO; return (0); case _PC_PATH_MAX: *ap->a_retval = PATH_MAX; return (0); case _PC_ACL_EXTENDED: case _PC_ACL_NFS4: case _PC_CAP_PRESENT: case _PC_DEALLOC_PRESENT: case _PC_INF_PRESENT: case _PC_MAC_PRESENT: case _PC_NAMEDATTR_ENABLED: case _PC_HAS_NAMEDATTR: case _PC_HAS_HIDDENSYSTEM: case _PC_CLONE_BLKSIZE: *ap->a_retval = 0; return (0); default: return (EINVAL); } /* NOTREACHED */ } /* * Standard lock, unlock and islocked functions. */ int vop_stdlock(struct vop_lock1_args *ap) { struct vnode *vp = ap->a_vp; struct mtx *ilk; ilk = VI_MTX(vp); return (lockmgr_lock_flags(vp->v_vnlock, ap->a_flags, &ilk->lock_object, ap->a_file, ap->a_line)); } /* See above. */ int vop_stdunlock(struct vop_unlock_args *ap) { struct vnode *vp = ap->a_vp; return (lockmgr_unlock(vp->v_vnlock)); } /* See above. */ int vop_stdislocked(struct vop_islocked_args *ap) { return (lockstatus(ap->a_vp->v_vnlock)); } /* * Variants of the above set. * * Differences are: * - shared locking disablement is not supported * - v_vnlock pointer is not honored */ int vop_lock(struct vop_lock1_args *ap) { struct vnode *vp = ap->a_vp; int flags = ap->a_flags; struct mtx *ilk; MPASS(vp->v_vnlock == &vp->v_lock); if (__predict_false((flags & ~(LK_TYPE_MASK | LK_NODDLKTREAT | LK_RETRY)) != 0)) goto other; switch (flags & LK_TYPE_MASK) { case LK_SHARED: return (lockmgr_slock(&vp->v_lock, flags, ap->a_file, ap->a_line)); case LK_EXCLUSIVE: return (lockmgr_xlock(&vp->v_lock, flags, ap->a_file, ap->a_line)); } other: ilk = VI_MTX(vp); return (lockmgr_lock_flags(&vp->v_lock, flags, &ilk->lock_object, ap->a_file, ap->a_line)); } int vop_unlock(struct vop_unlock_args *ap) { struct vnode *vp = ap->a_vp; MPASS(vp->v_vnlock == &vp->v_lock); return (lockmgr_unlock(&vp->v_lock)); } int vop_islocked(struct vop_islocked_args *ap) { struct vnode *vp = ap->a_vp; MPASS(vp->v_vnlock == &vp->v_lock); return (lockstatus(&vp->v_lock)); } /* * Return true for select/poll. */ int vop_nopoll(struct vop_poll_args *ap) { if (ap->a_events & ~POLLSTANDARD) return (POLLNVAL); return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); } /* * Implement poll for local filesystems that support it. */ int vop_stdpoll(struct vop_poll_args *ap) { if (ap->a_events & ~POLLSTANDARD) return (vn_pollrecord(ap->a_vp, ap->a_td, ap->a_events)); return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); } /* * Return our mount point, as we will take charge of the writes. */ int vop_stdgetwritemount(struct vop_getwritemount_args *ap) { struct mount *mp; struct vnode *vp; /* * Note that having a reference does not prevent forced unmount from * setting ->v_mount to NULL after the lock gets released. This is of * no consequence for typical consumers (most notably vn_start_write) * since in this case the vnode is VIRF_DOOMED. Unmount might have * progressed far enough that its completion is only delayed by the * reference obtained here. The consumer only needs to concern itself * with releasing it. */ vp = ap->a_vp; mp = vfs_ref_from_vp(vp); *(ap->a_mpp) = mp; return (0); } /* * If the file system doesn't implement VOP_BMAP, then return sensible defaults: * - Return the vnode's bufobj instead of any underlying device's bufobj * - Calculate the physical block number as if there were equal size * consecutive blocks, but * - Report no contiguous runs of blocks. */ int vop_stdbmap(struct vop_bmap_args *ap) { if (ap->a_bop != NULL) *ap->a_bop = &ap->a_vp->v_bufobj; if (ap->a_bnp != NULL) *ap->a_bnp = ap->a_bn * btodb(ap->a_vp->v_mount->mnt_stat.f_iosize); if (ap->a_runp != NULL) *ap->a_runp = 0; if (ap->a_runb != NULL) *ap->a_runb = 0; return (0); } int vop_stdfsync(struct vop_fsync_args *ap) { return (vn_fsync_buf(ap->a_vp, ap->a_waitfor)); } static int vop_stdfdatasync(struct vop_fdatasync_args *ap) { return (VOP_FSYNC(ap->a_vp, MNT_WAIT, ap->a_td)); } int vop_stdfdatasync_buf(struct vop_fdatasync_args *ap) { return (vn_fsync_buf(ap->a_vp, MNT_WAIT)); } /* XXX Needs good comment and more info in the manpage (VOP_GETPAGES(9)). */ int vop_stdgetpages(struct vop_getpages_args *ap) { return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count, ap->a_rbehind, ap->a_rahead, NULL, NULL); } static int vop_stdgetpages_async(struct vop_getpages_async_args *ap) { int error; error = VOP_GETPAGES(ap->a_vp, ap->a_m, ap->a_count, ap->a_rbehind, ap->a_rahead); if (ap->a_iodone != NULL) ap->a_iodone(ap->a_arg, ap->a_m, ap->a_count, error); return (error); } int vop_stdkqfilter(struct vop_kqfilter_args *ap) { return vfs_kqfilter(ap); } /* XXX Needs good comment and more info in the manpage (VOP_PUTPAGES(9)). */ int vop_stdputpages(struct vop_putpages_args *ap) { return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count, ap->a_sync, ap->a_rtvals); } int vop_stdvptofh(struct vop_vptofh_args *ap) { return (EOPNOTSUPP); } int vop_stdvptocnp(struct vop_vptocnp_args *ap) { struct vnode *const vp = ap->a_vp; struct vnode **const dvp = ap->a_vpp; char *buf = ap->a_buf; size_t *buflen = ap->a_buflen; char *dirbuf; int i = *buflen; int error = 0, covered = 0; int eofflag, flags, locked; size_t dirbuflen, len; off_t off; ino_t fileno; struct vattr va; struct nameidata nd; struct thread *const td = curthread; struct ucred *const cred = td->td_ucred; struct dirent *dp; struct vnode *mvp; if (vp->v_type != VDIR) return (ENOENT); error = VOP_GETATTR(vp, &va, cred); if (error) return (error); - VREF(vp); + vref(vp); locked = VOP_ISLOCKED(vp); VOP_UNLOCK(vp); NDINIT_ATVP(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF, UIO_SYSSPACE, "..", vp); flags = FREAD; error = vn_open_cred(&nd, &flags, 0, VN_OPEN_NOAUDIT, cred, NULL); if (error) { vn_lock(vp, locked | LK_RETRY); return (error); } NDFREE_PNBUF(&nd); mvp = *dvp = nd.ni_vp; if (vp->v_mount != (*dvp)->v_mount && ((*dvp)->v_vflag & VV_ROOT) && ((*dvp)->v_mount->mnt_flag & MNT_UNION)) { *dvp = (*dvp)->v_mount->mnt_vnodecovered; - VREF(mvp); + vref(mvp); VOP_UNLOCK(mvp); vn_close(mvp, FREAD, cred, td); - VREF(*dvp); + vref(*dvp); vn_lock(*dvp, LK_SHARED | LK_RETRY); covered = 1; } fileno = va.va_fileid; dirbuflen = MAX(DEV_BSIZE, GENERIC_MAXDIRSIZ); if (dirbuflen < va.va_blocksize) dirbuflen = va.va_blocksize; dirbuf = malloc(dirbuflen, M_TEMP, M_WAITOK); if ((*dvp)->v_type != VDIR) { error = ENOENT; goto out; } len = 0; off = 0; eofflag = 0; for (;;) { /* call VOP_READDIR of parent */ error = vn_dir_next_dirent(*dvp, td, dirbuf, dirbuflen, &dp, &len, &off, &eofflag); if (error != 0) goto out; if (len == 0) { error = ENOENT; goto out; } if ((dp->d_type != DT_WHT) && (dp->d_fileno == fileno)) { if (covered) { VOP_UNLOCK(*dvp); vn_lock(mvp, LK_SHARED | LK_RETRY); if (dirent_exists(mvp, dp->d_name, td) == 0) { error = ENOENT; VOP_UNLOCK(mvp); vn_lock(*dvp, LK_SHARED | LK_RETRY); goto out; } VOP_UNLOCK(mvp); vn_lock(*dvp, LK_SHARED | LK_RETRY); } i -= dp->d_namlen; if (i < 0) { error = ENOMEM; goto out; } if (dp->d_namlen == 1 && dp->d_name[0] == '.') { error = ENOENT; } else { bcopy(dp->d_name, buf + i, dp->d_namlen); error = 0; } goto out; } } out: free(dirbuf, M_TEMP); if (!error) { *buflen = i; vref(*dvp); } if (covered) { vput(*dvp); vrele(mvp); } else { VOP_UNLOCK(mvp); vn_close(mvp, FREAD, cred, td); } vn_lock(vp, locked | LK_RETRY); return (error); } int vop_stdallocate(struct vop_allocate_args *ap) { #ifdef __notyet__ struct statfs *sfs; off_t maxfilesize = 0; #endif struct iovec aiov; struct vattr vattr, *vap; struct uio auio; off_t fsize, len, cur, offset; uint8_t *buf; struct thread *td; struct vnode *vp; size_t iosize; int error; buf = NULL; error = 0; td = curthread; vap = &vattr; vp = ap->a_vp; len = *ap->a_len; offset = *ap->a_offset; error = VOP_GETATTR(vp, vap, ap->a_cred); if (error != 0) goto out; fsize = vap->va_size; iosize = vap->va_blocksize; if (iosize == 0) iosize = BLKDEV_IOSIZE; if (iosize > maxphys) iosize = maxphys; buf = malloc(iosize, M_TEMP, M_WAITOK); #ifdef __notyet__ /* * Check if the filesystem sets f_maxfilesize; if not use * VOP_SETATTR to perform the check. */ sfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = VFS_STATFS(vp->v_mount, sfs, td); if (error == 0) maxfilesize = sfs->f_maxfilesize; free(sfs, M_STATFS); if (error != 0) goto out; if (maxfilesize) { if (offset > maxfilesize || len > maxfilesize || offset + len > maxfilesize) { error = EFBIG; goto out; } } else #endif if (offset + len > vap->va_size) { /* * Test offset + len against the filesystem's maxfilesize. */ VATTR_NULL(vap); vap->va_size = offset + len; error = VOP_SETATTR(vp, vap, ap->a_cred); if (error != 0) goto out; VATTR_NULL(vap); vap->va_size = fsize; error = VOP_SETATTR(vp, vap, ap->a_cred); if (error != 0) goto out; } for (;;) { /* * Read and write back anything below the nominal file * size. There's currently no way outside the filesystem * to know whether this area is sparse or not. */ cur = iosize; if ((offset % iosize) != 0) cur -= (offset % iosize); if (cur > len) cur = len; if (offset < fsize) { aiov.iov_base = buf; aiov.iov_len = cur; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = offset; auio.uio_resid = cur; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_READ; auio.uio_td = td; error = VOP_READ(vp, &auio, ap->a_ioflag, ap->a_cred); if (error != 0) break; if (auio.uio_resid > 0) { bzero(buf + cur - auio.uio_resid, auio.uio_resid); } } else { bzero(buf, cur); } aiov.iov_base = buf; aiov.iov_len = cur; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = offset; auio.uio_resid = cur; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_td = td; error = VOP_WRITE(vp, &auio, ap->a_ioflag, ap->a_cred); if (error != 0) break; len -= cur; offset += cur; if (len == 0) break; if (should_yield()) break; } out: *ap->a_len = len; *ap->a_offset = offset; free(buf, M_TEMP); return (error); } static int vp_zerofill(struct vnode *vp, struct vattr *vap, off_t *offsetp, off_t *lenp, int ioflag, struct ucred *cred) { int iosize; int error = 0; struct iovec aiov; struct uio auio; struct thread *td; off_t offset, len; iosize = vap->va_blocksize; td = curthread; offset = *offsetp; len = *lenp; if (iosize == 0) iosize = BLKDEV_IOSIZE; /* If va_blocksize is 512 bytes, iosize will be 4 kilobytes */ iosize = min(iosize * 8, ZERO_REGION_SIZE); while (len > 0) { int xfersize = iosize; if (offset % iosize != 0) xfersize -= offset % iosize; if (xfersize > len) xfersize = len; aiov.iov_base = __DECONST(void *, zero_region); aiov.iov_len = xfersize; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = offset; auio.uio_resid = xfersize; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_td = td; error = VOP_WRITE(vp, &auio, ioflag, cred); if (error != 0) { len -= xfersize - auio.uio_resid; offset += xfersize - auio.uio_resid; break; } len -= xfersize; offset += xfersize; } *offsetp = offset; *lenp = len; return (error); } int vop_stddeallocate(struct vop_deallocate_args *ap) { struct vnode *vp; off_t offset, len; struct ucred *cred; int error; struct vattr va; off_t noff, xfersize, rem; vp = ap->a_vp; offset = *ap->a_offset; cred = ap->a_cred; error = VOP_GETATTR(vp, &va, cred); if (error) return (error); len = omin((off_t)va.va_size - offset, *ap->a_len); while (len > 0) { noff = offset; error = vn_bmap_seekhole_locked(vp, FIOSEEKDATA, &noff, cred); if (error) { if (error != ENXIO) /* XXX: Is it okay to fallback further? */ goto out; /* * No more data region to be filled */ offset += len; len = 0; error = 0; break; } KASSERT(noff >= offset, ("FIOSEEKDATA going backward")); if (noff != offset) { xfersize = omin(noff - offset, len); len -= xfersize; offset += xfersize; if (len == 0) break; } error = vn_bmap_seekhole_locked(vp, FIOSEEKHOLE, &noff, cred); if (error) goto out; /* Fill zeroes */ xfersize = rem = omin(noff - offset, len); error = vp_zerofill(vp, &va, &offset, &rem, ap->a_ioflag, cred); if (error) { len -= xfersize - rem; goto out; } len -= xfersize; if (should_yield()) break; } /* Handle the case when offset is beyond EOF */ if (len < 0) len = 0; out: *ap->a_offset = offset; *ap->a_len = len; return (error); } int vop_stdadvise(struct vop_advise_args *ap) { struct vnode *vp; struct bufobj *bo; uintmax_t bstart, bend; daddr_t startn, endn; int bsize, error; vp = ap->a_vp; switch (ap->a_advice) { case POSIX_FADV_WILLNEED: /* * Do nothing for now. Filesystems should provide a * custom method which starts an asynchronous read of * the requested region. */ error = 0; break; case POSIX_FADV_DONTNEED: error = 0; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (VN_IS_DOOMED(vp)) { VOP_UNLOCK(vp); break; } /* * Round to block boundaries (and later possibly further to * page boundaries). Applications cannot reasonably be aware * of the boundaries, and the rounding must be to expand at * both extremities to cover enough. It still doesn't cover * read-ahead. For partial blocks, this gives unnecessary * discarding of buffers but is efficient enough since the * pages usually remain in VMIO for some time. */ bsize = vp->v_bufobj.bo_bsize; bstart = rounddown(ap->a_start, bsize); bend = ap->a_end; bend = roundup(bend, bsize); /* * Deactivate pages in the specified range from the backing VM * object. Pages that are resident in the buffer cache will * remain wired until their corresponding buffers are released * below. */ if (vp->v_object != NULL) { VM_OBJECT_RLOCK(vp->v_object); vm_object_page_noreuse(vp->v_object, OFF_TO_IDX(trunc_page(bstart)), OFF_TO_IDX(round_page(bend))); VM_OBJECT_RUNLOCK(vp->v_object); } bo = &vp->v_bufobj; startn = bstart / bsize; endn = bend / bsize; BO_RLOCK(bo); error = bnoreuselist(&bo->bo_clean, bo, startn, endn); if (error == 0) error = bnoreuselist(&bo->bo_dirty, bo, startn, endn); BO_RUNLOCK(bo); VOP_UNLOCK(vp); break; default: error = EINVAL; break; } return (error); } int vop_stdunp_bind(struct vop_unp_bind_args *ap) { ap->a_vp->v_unpcb = ap->a_unpcb; return (0); } int vop_stdunp_connect(struct vop_unp_connect_args *ap) { *ap->a_unpcb = ap->a_vp->v_unpcb; return (0); } int vop_stdunp_detach(struct vop_unp_detach_args *ap) { ap->a_vp->v_unpcb = NULL; return (0); } static int vop_stdis_text(struct vop_is_text_args *ap) { return ((int)atomic_load_int(&ap->a_vp->v_writecount) < 0); } int vop_stdset_text(struct vop_set_text_args *ap) { struct vnode *vp; int n; bool gotref; vp = ap->a_vp; n = atomic_load_int(&vp->v_writecount); for (;;) { if (__predict_false(n > 0)) { return (ETXTBSY); } /* * Transition point, we may need to grab a reference on the vnode. * * Take the ref early As a safety measure against bogus calls * to vop_stdunset_text. */ if (n == 0) { gotref = false; if ((vn_irflag_read(vp) & VIRF_TEXT_REF) != 0) { vref(vp); gotref = true; } if (atomic_fcmpset_int(&vp->v_writecount, &n, -1)) { return (0); } if (gotref) { vunref(vp); } continue; } MPASS(n < 0); if (atomic_fcmpset_int(&vp->v_writecount, &n, n - 1)) { return (0); } } __assert_unreachable(); } static int vop_stdunset_text(struct vop_unset_text_args *ap) { struct vnode *vp; int n; vp = ap->a_vp; n = atomic_load_int(&vp->v_writecount); for (;;) { if (__predict_false(n >= 0)) { return (EINVAL); } /* * Transition point, we may need to release a reference on the vnode. */ if (n == -1) { if (atomic_fcmpset_int(&vp->v_writecount, &n, 0)) { if ((vn_irflag_read(vp) & VIRF_TEXT_REF) != 0) { vunref(vp); } return (0); } continue; } MPASS(n < -1); if (atomic_fcmpset_int(&vp->v_writecount, &n, n + 1)) { return (0); } } __assert_unreachable(); } static __always_inline int vop_stdadd_writecount_impl(struct vop_add_writecount_args *ap, bool handle_msync) { struct vnode *vp; struct mount *mp __diagused; int n; vp = ap->a_vp; #ifdef INVARIANTS mp = vp->v_mount; if (mp != NULL) { if (handle_msync) { VNPASS((mp->mnt_kern_flag & MNTK_NOMSYNC) == 0, vp); } else { VNPASS((mp->mnt_kern_flag & MNTK_NOMSYNC) != 0, vp); } } #endif n = atomic_load_int(&vp->v_writecount); for (;;) { if (__predict_false(n < 0)) { return (ETXTBSY); } VNASSERT(n + ap->a_inc >= 0, vp, ("neg writecount increment %d + %d = %d", n, ap->a_inc, n + ap->a_inc)); if (n == 0) { if (handle_msync) { vlazy(vp); } } if (atomic_fcmpset_int(&vp->v_writecount, &n, n + ap->a_inc)) { return (0); } } __assert_unreachable(); } int vop_stdadd_writecount(struct vop_add_writecount_args *ap) { return (vop_stdadd_writecount_impl(ap, true)); } int vop_stdadd_writecount_nomsync(struct vop_add_writecount_args *ap) { return (vop_stdadd_writecount_impl(ap, false)); } int vop_stdneed_inactive(struct vop_need_inactive_args *ap) { return (1); } int vop_stdinotify(struct vop_inotify_args *ap) { vn_inotify(ap->a_vp, ap->a_dvp, ap->a_cnp, ap->a_event, ap->a_cookie); return (0); } int vop_stdinotify_add_watch(struct vop_inotify_add_watch_args *ap) { return (vn_inotify_add_watch(ap->a_vp, ap->a_sc, ap->a_mask, ap->a_wdp, ap->a_td)); } int vop_stdioctl(struct vop_ioctl_args *ap) { struct vnode *vp; struct vattr va; off_t *offp; int error; switch (ap->a_command) { case FIOSEEKDATA: case FIOSEEKHOLE: vp = ap->a_vp; error = vn_lock(vp, LK_SHARED); if (error != 0) return (EBADF); if (vp->v_type == VREG) error = VOP_GETATTR(vp, &va, ap->a_cred); else error = ENOTTY; if (error == 0) { offp = ap->a_data; if (*offp < 0 || *offp >= va.va_size) error = ENXIO; else if (ap->a_command == FIOSEEKHOLE) *offp = va.va_size; } VOP_UNLOCK(vp); break; default: error = ENOTTY; break; } return (error); } /* * vfs default ops * used to fill the vfs function table to get reasonable default return values. */ int vfs_stdroot(struct mount *mp, int flags, struct vnode **vpp) { return (EOPNOTSUPP); } int vfs_stdstatfs(struct mount *mp, struct statfs *sbp) { return (EOPNOTSUPP); } int vfs_stdquotactl(struct mount *mp, int cmds, uid_t uid, void *arg, bool *mp_busy) { return (EOPNOTSUPP); } int vfs_stdsync(struct mount *mp, int waitfor) { struct vnode *vp, *mvp; struct thread *td; int error, lockreq, allerror = 0; td = curthread; lockreq = LK_EXCLUSIVE | LK_INTERLOCK; if (waitfor != MNT_WAIT) lockreq |= LK_NOWAIT; /* * Force stale buffer cache information to be flushed. */ loop: MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { if (vp->v_bufobj.bo_dirty.bv_cnt == 0) { VI_UNLOCK(vp); continue; } if ((error = vget(vp, lockreq)) != 0) { if (error == ENOENT) { MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); goto loop; } continue; } error = VOP_FSYNC(vp, waitfor, td); if (error) allerror = error; vput(vp); } return (allerror); } int vfs_stdnosync(struct mount *mp, int waitfor) { return (0); } static int vop_stdcopy_file_range(struct vop_copy_file_range_args *ap) { int error; error = vn_generic_copy_file_range(ap->a_invp, ap->a_inoffp, ap->a_outvp, ap->a_outoffp, ap->a_lenp, ap->a_flags, ap->a_incred, ap->a_outcred, ap->a_fsizetd); return (error); } int vfs_stdvget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { return (EOPNOTSUPP); } int vfs_stdfhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { return (EOPNOTSUPP); } int vfs_stdinit(struct vfsconf *vfsp) { return (0); } int vfs_stduninit(struct vfsconf *vfsp) { return(0); } int vfs_stdextattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, int attrnamespace, const char *attrname) { if (filename_vp != NULL) VOP_UNLOCK(filename_vp); return (EOPNOTSUPP); } int vfs_stdsysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) { return (EOPNOTSUPP); } static vop_bypass_t * bp_by_off(struct vop_vector *vop, struct vop_generic_args *a) { return (*(vop_bypass_t **)((char *)vop + a->a_desc->vdesc_vop_offset)); } int vop_sigdefer(struct vop_vector *vop, struct vop_generic_args *a) { vop_bypass_t *bp; int prev_stops, rc; bp = bp_by_off(vop, a); MPASS(bp != NULL); prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); rc = bp(a); sigallowstop(prev_stops); return (rc); } static int vop_stdstat(struct vop_stat_args *a) { struct vattr vattr; struct vattr *vap; struct vnode *vp; struct stat *sb; int error; u_short mode; vp = a->a_vp; sb = a->a_sb; error = vop_stat_helper_pre(a); if (error != 0) return (error); vap = &vattr; /* * Initialize defaults for new and unusual fields, so that file * systems which don't support these fields don't need to know * about them. */ vap->va_birthtime.tv_sec = -1; vap->va_birthtime.tv_nsec = 0; vap->va_fsid = VNOVAL; vap->va_gen = 0; vap->va_rdev = NODEV; vap->va_filerev = 0; vap->va_bsdflags = 0; error = VOP_GETATTR(vp, vap, a->a_active_cred); if (error) goto out; /* * Zero the spare stat fields */ bzero(sb, sizeof *sb); /* * Copy from vattr table */ if (vap->va_fsid != VNOVAL) sb->st_dev = vap->va_fsid; else sb->st_dev = vp->v_mount->mnt_stat.f_fsid.val[0]; sb->st_ino = vap->va_fileid; mode = vap->va_mode; switch (vap->va_type) { case VREG: mode |= S_IFREG; break; case VDIR: mode |= S_IFDIR; break; case VBLK: mode |= S_IFBLK; break; case VCHR: mode |= S_IFCHR; break; case VLNK: mode |= S_IFLNK; break; case VSOCK: mode |= S_IFSOCK; break; case VFIFO: mode |= S_IFIFO; break; default: error = EBADF; goto out; } sb->st_mode = mode; sb->st_nlink = vap->va_nlink; sb->st_uid = vap->va_uid; sb->st_gid = vap->va_gid; sb->st_rdev = vap->va_rdev; if (vap->va_size > OFF_MAX) { error = EOVERFLOW; goto out; } sb->st_size = vap->va_size; sb->st_atim.tv_sec = vap->va_atime.tv_sec; sb->st_atim.tv_nsec = vap->va_atime.tv_nsec; sb->st_mtim.tv_sec = vap->va_mtime.tv_sec; sb->st_mtim.tv_nsec = vap->va_mtime.tv_nsec; sb->st_ctim.tv_sec = vap->va_ctime.tv_sec; sb->st_ctim.tv_nsec = vap->va_ctime.tv_nsec; sb->st_birthtim.tv_sec = vap->va_birthtime.tv_sec; sb->st_birthtim.tv_nsec = vap->va_birthtime.tv_nsec; /* * According to www.opengroup.org, the meaning of st_blksize is * "a filesystem-specific preferred I/O block size for this * object. In some filesystem types, this may vary from file * to file" * Use minimum/default of PAGE_SIZE (e.g. for VCHR). */ sb->st_blksize = max(PAGE_SIZE, vap->va_blocksize); sb->st_flags = vap->va_flags; sb->st_blocks = vap->va_bytes / S_BLKSIZE; sb->st_gen = vap->va_gen; sb->st_filerev = vap->va_filerev; sb->st_bsdflags = vap->va_bsdflags; out: return (vop_stat_helper_post(a, error)); } static int vop_stdread_pgcache(struct vop_read_pgcache_args *ap __unused) { return (EJUSTRETURN); } static int vop_stdvput_pair(struct vop_vput_pair_args *ap) { struct vnode *dvp, *vp, **vpp; dvp = ap->a_dvp; vpp = ap->a_vpp; vput(dvp); if (vpp != NULL && ap->a_unlock_vp && (vp = *vpp) != NULL) vput(vp); return (0); } static int vop_stdgetlowvnode(struct vop_getlowvnode_args *ap) { vref(ap->a_vp); *ap->a_vplp = ap->a_vp; return (0); } diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 2f8b88783f3d..39c7da803de1 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -1,1681 +1,1681 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 #include "opt_capsicum.h" #include "opt_ktrace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KTRACE #include #endif #ifdef INVARIANTS #include #endif #include #include #include #ifdef INVARIANTS static void NDVALIDATE_impl(struct nameidata *, int); #define NDVALIDATE(ndp) NDVALIDATE_impl(ndp, __LINE__) #else #define NDVALIDATE(ndp) #endif /* * Reset ndp to its original state. */ #define NDRESET(ndp) do { \ NDREINIT_DBG(ndp); \ ndp->ni_resflags = 0; \ ndp->ni_cnd.cn_flags &= ~NAMEI_INTERNAL_FLAGS; \ } while (0) /* * Prepare namei() to restart. Reset components to its original state and set * ISRESTARTED flag which signals the underlying lookup code to change the root * from ABI root to actual root and prevents a further restarts. */ #define NDRESTART(ndp) do { \ NDRESET(ndp); \ ndp->ni_cnd.cn_flags |= ISRESTARTED; \ } while (0) #ifdef KTRACE #define NIKTRCAPFAIL(path) ktrcapfail(CAPFAIL_NAMEI, (path)) #else #define NIKTRCAPFAIL(path) #endif #define NI_CAP_VIOLATION(ndp, path) do { \ NIKTRCAPFAIL(path); \ (ndp)->ni_lcf &= ~NI_LCF_KTR_FLAGS; \ } while (0) SDT_PROVIDER_DEFINE(vfs); SDT_PROBE_DEFINE4(vfs, namei, lookup, entry, "struct vnode *", "char *", "unsigned long", "bool"); SDT_PROBE_DEFINE4(vfs, namei, lookup, return, "int", "struct vnode *", "bool", "struct nameidata"); /* Allocation zone for namei. */ uma_zone_t namei_zone; /* Placeholder vnode for mp traversal. */ static struct vnode *vp_crossmp; static int crossmp_vop_islocked(struct vop_islocked_args *ap) { return (LK_SHARED); } static int crossmp_vop_lock1(struct vop_lock1_args *ap) { struct vnode *vp; struct lock *lk __diagused; int flags; vp = ap->a_vp; lk = vp->v_vnlock; flags = ap->a_flags; KASSERT((flags & (LK_SHARED | LK_NOWAIT)) == (LK_SHARED | LK_NOWAIT), ("%s: invalid lock request 0x%x for crossmp", __func__, flags)); if ((flags & LK_INTERLOCK) != 0) VI_UNLOCK(vp); LOCK_LOG_LOCK("SLOCK", &lk->lock_object, 0, 0, ap->a_file, ap->a_line); return (0); } static int crossmp_vop_unlock(struct vop_unlock_args *ap) { struct vnode *vp; struct lock *lk __diagused; vp = ap->a_vp; lk = vp->v_vnlock; LOCK_LOG_LOCK("SUNLOCK", &lk->lock_object, 0, 0, LOCK_FILE, LOCK_LINE); return (0); } static struct vop_vector crossmp_vnodeops = { .vop_default = &default_vnodeops, .vop_islocked = crossmp_vop_islocked, .vop_lock1 = crossmp_vop_lock1, .vop_unlock = crossmp_vop_unlock, }; /* * VFS_VOP_VECTOR_REGISTER(crossmp_vnodeops) is not used here since the vnode * gets allocated early. See nameiinit for the direct call below. */ struct nameicap_tracker { TAILQ_ENTRY(nameicap_tracker) nm_link; struct mount *mp; }; /* Zone for cap mode tracker elements used for dotdot capability checks. */ MALLOC_DEFINE(M_NAMEITRACKER, "namei_tracker", "namei tracking for dotdot"); static void nameiinit(void *dummy __unused) { namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); vfs_vector_op_register(&crossmp_vnodeops); getnewvnode("crossmp", NULL, &crossmp_vnodeops, &vp_crossmp); vp_crossmp->v_state = VSTATE_CONSTRUCTED; vp_crossmp->v_irflag |= VIRF_CROSSMP; } SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL); static int lookup_cap_dotdot = 1; SYSCTL_INT(_vfs, OID_AUTO, lookup_cap_dotdot, CTLFLAG_RWTUN, &lookup_cap_dotdot, 0, "enables \"..\" components in path lookup in capability mode"); static int lookup_cap_dotdot_nonlocal = 1; SYSCTL_INT(_vfs, OID_AUTO, lookup_cap_dotdot_nonlocal, CTLFLAG_RWTUN, &lookup_cap_dotdot_nonlocal, 0, "enables \"..\" components in path lookup in capability mode " "on non-local mount"); static int nameicap_tracker_add(struct nameidata *ndp, struct vnode *dp) { struct nameicap_tracker *nt; struct mount *mp; int error; if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0 || dp->v_type != VDIR) return (0); mp = NULL; error = VOP_GETWRITEMOUNT(dp, &mp); if (error != 0) return (error); nt = TAILQ_LAST(&ndp->ni_cap_tracker, nameicap_tracker_head); if (nt != NULL && nt->mp == mp) { vfs_rel(mp); return (0); } nt = malloc(sizeof(*nt), M_NAMEITRACKER, M_WAITOK); nt->mp = mp; error = lockmgr(&mp->mnt_renamelock, LK_SHARED | LK_NOWAIT, 0); if (error != 0) { MPASS(ndp->ni_nctrack_mnt == NULL); ndp->ni_nctrack_mnt = mp; free(nt, M_NAMEITRACKER); error = ERESTART; } else { TAILQ_INSERT_TAIL(&ndp->ni_cap_tracker, nt, nm_link); } return (error); } static void nameicap_cleanup(struct nameidata *ndp, int error) { struct nameicap_tracker *nt, *nt1; struct mount *mp; KASSERT((ndp->ni_nctrack_mnt == NULL && TAILQ_EMPTY(&ndp->ni_cap_tracker)) || (ndp->ni_lcf & NI_LCF_CAP_DOTDOT) != 0, ("tracker active and not strictrelative")); TAILQ_FOREACH_SAFE(nt, &ndp->ni_cap_tracker, nm_link, nt1) { mp = nt->mp; lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0); vfs_rel(mp); TAILQ_REMOVE(&ndp->ni_cap_tracker, nt, nm_link); free(nt, M_NAMEITRACKER); } mp = ndp->ni_nctrack_mnt; if (mp != NULL) { if (error == ERESTART) { lockmgr(&mp->mnt_renamelock, LK_EXCLUSIVE, 0); lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0); } vfs_rel(mp); ndp->ni_nctrack_mnt = NULL; } } /* * For dotdot lookups in capability mode, disallow walking over the * directory no_rbeneath_dpp that was used as the starting point of * the lookup. Since we take the mnt_renamelocks of all mounts we * ever walked over during lookup, parallel renames are disabled. * This prevents the situation where we circumvent walk over * ni_rbeneath_dpp following dotdots. * * Also allow to force failure of dotdot lookups for non-local * filesystems, where external agents might assist local lookups to * escape the compartment. */ static int nameicap_check_dotdot(struct nameidata *ndp, struct vnode *dp) { struct mount *mp; if (dp == NULL || dp->v_type != VDIR || (ndp->ni_lcf & NI_LCF_STRICTREL) == 0) return (0); if (__predict_false((ndp->ni_lcf & (NI_LCF_STRICTREL_KTR | NI_LCF_CAP_DOTDOT_KTR)) == NI_LCF_STRICTREL_KTR)) NI_CAP_VIOLATION(ndp, ndp->ni_cnd.cn_pnbuf); if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0) goto violation; if (dp == ndp->ni_rbeneath_dpp) goto violation; mp = dp->v_mount; if (lookup_cap_dotdot_nonlocal == 0 && mp != NULL && (mp->mnt_flag & MNT_LOCAL) == 0) goto violation; return (0); violation: if (__predict_false((ndp->ni_lcf & NI_LCF_STRICTREL_KTR) != 0)) NI_CAP_VIOLATION(ndp, ndp->ni_cnd.cn_pnbuf); return (ENOTCAPABLE); } static void namei_cleanup_cnp(struct componentname *cnp) { uma_zfree(namei_zone, cnp->cn_pnbuf); cnp->cn_pnbuf = NULL; cnp->cn_nameptr = NULL; } static int namei_handle_root(struct nameidata *ndp, struct vnode **dpp) { struct componentname *cnp; cnp = &ndp->ni_cnd; if (__predict_false((ndp->ni_lcf & (NI_LCF_STRICTREL | NI_LCF_STRICTREL_KTR)) != 0)) { if ((ndp->ni_lcf & NI_LCF_STRICTREL_KTR) != 0) NI_CAP_VIOLATION(ndp, cnp->cn_pnbuf); if ((ndp->ni_lcf & NI_LCF_STRICTREL) != 0) return (ENOTCAPABLE); } while (*(cnp->cn_nameptr) == '/') { cnp->cn_nameptr++; ndp->ni_pathlen--; } *dpp = ndp->ni_rootdir; vrefact(*dpp); return (0); } static int namei_setup(struct nameidata *ndp, struct vnode **dpp, struct pwd **pwdp) { struct componentname *cnp; struct thread *td; struct pwd *pwd; int error; bool startdir_used; cnp = &ndp->ni_cnd; td = curthread; startdir_used = false; *pwdp = NULL; *dpp = NULL; #ifdef CAPABILITY_MODE /* * In capability mode, lookups must be restricted to happen in * the subtree with the root specified by the file descriptor: * - The root must be real file descriptor, not the pseudo-descriptor * AT_FDCWD. * - The passed path must be relative and not absolute. * - If lookup_cap_dotdot is disabled, path must not contain the * '..' components. * - If lookup_cap_dotdot is enabled, we verify that all '..' * components lookups result in the directories which were * previously walked by us, which prevents an escape from * the relative root. */ if ((cnp->cn_flags & NOCAPCHECK) == 0) { if (CAP_TRACING(td)) { ndp->ni_lcf |= NI_LCF_STRICTREL_KTR; if (ndp->ni_dirfd == AT_FDCWD) NI_CAP_VIOLATION(ndp, "AT_FDCWD"); } if (IN_CAPABILITY_MODE(td)) { ndp->ni_lcf |= NI_LCF_STRICTREL; ndp->ni_resflags |= NIRES_STRICTREL; if (ndp->ni_dirfd == AT_FDCWD) return (ECAPMODE); } } #endif error = 0; /* * Get starting point for the translation. */ pwd = pwd_hold(td); /* * The reference on ni_rootdir is acquired in the block below to avoid * back-to-back atomics for absolute lookups. */ namei_setup_rootdir(ndp, cnp, pwd); ndp->ni_topdir = pwd->pwd_jdir; if (cnp->cn_pnbuf[0] == '/') { ndp->ni_resflags |= NIRES_ABS; error = namei_handle_root(ndp, dpp); } else { if (ndp->ni_startdir != NULL) { *dpp = ndp->ni_startdir; startdir_used = true; } else if (ndp->ni_dirfd == AT_FDCWD) { *dpp = pwd->pwd_cdir; vrefact(*dpp); } else { if (cnp->cn_flags & AUDITVNODE1) AUDIT_ARG_ATFD1(ndp->ni_dirfd); if (cnp->cn_flags & AUDITVNODE2) AUDIT_ARG_ATFD2(ndp->ni_dirfd); error = fgetvp_lookup(ndp, dpp); } if (error == 0 && (*dpp)->v_type != VDIR && (cnp->cn_flags & OPENNAMED) == 0 && (cnp->cn_pnbuf[0] != '\0' || (cnp->cn_flags & EMPTYPATH) == 0)) error = ENOTDIR; } if (error == 0 && (cnp->cn_flags & RBENEATH) != 0) { if (cnp->cn_pnbuf[0] == '/') { error = ENOTCAPABLE; } else if ((ndp->ni_lcf & NI_LCF_STRICTREL) == 0) { ndp->ni_lcf |= NI_LCF_STRICTREL | NI_LCF_CAP_DOTDOT; } } if (error == 0 && (ndp->ni_lcf & NI_LCF_STRICTREL) != 0) ndp->ni_rbeneath_dpp = *dpp; /* * If we are auditing the kernel pathname, save the user pathname. */ if (AUDITING_TD(td)) { if (cnp->cn_flags & AUDITVNODE1) AUDIT_ARG_UPATH1_VP(td, ndp->ni_rootdir, *dpp, cnp->cn_pnbuf); if (cnp->cn_flags & AUDITVNODE2) AUDIT_ARG_UPATH2_VP(td, ndp->ni_rootdir, *dpp, cnp->cn_pnbuf); } if (ndp->ni_startdir != NULL && !startdir_used) vrele(ndp->ni_startdir); if (error != 0) { if (*dpp != NULL) vrele(*dpp); pwd_drop(pwd); return (error); } if (lookup_cap_dotdot != 0) { if ((ndp->ni_lcf & NI_LCF_STRICTREL_KTR) != 0) ndp->ni_lcf |= NI_LCF_CAP_DOTDOT_KTR; if ((ndp->ni_lcf & NI_LCF_STRICTREL) != 0) ndp->ni_lcf |= NI_LCF_CAP_DOTDOT; } SDT_PROBE4(vfs, namei, lookup, entry, *dpp, cnp->cn_pnbuf, cnp->cn_flags, false); *pwdp = pwd; return (0); } static int namei_getpath(struct nameidata *ndp) { struct componentname *cnp; int error; cnp = &ndp->ni_cnd; /* * Get a buffer for the name to be translated, and copy the * name into the buffer. */ cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); if (ndp->ni_segflg == UIO_SYSSPACE) { error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, MAXPATHLEN, &ndp->ni_pathlen); } else { error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, MAXPATHLEN, &ndp->ni_pathlen); } return (error); } static int namei_emptypath(struct nameidata *ndp) { struct componentname *cnp; struct pwd *pwd; struct vnode *dp; int error; cnp = &ndp->ni_cnd; MPASS(*cnp->cn_pnbuf == '\0'); MPASS((cnp->cn_flags & EMPTYPATH) != 0); MPASS((cnp->cn_flags & (LOCKPARENT | WANTPARENT)) == 0); ndp->ni_resflags |= NIRES_EMPTYPATH; error = namei_setup(ndp, &dp, &pwd); if (error != 0) { goto errout; } /* * Usecount on dp already provided by namei_setup. */ ndp->ni_vp = dp; pwd_drop(pwd); NDVALIDATE(ndp); if ((cnp->cn_flags & LOCKLEAF) != 0) { VOP_LOCK(dp, (cnp->cn_flags & LOCKSHARED) != 0 ? LK_SHARED : LK_EXCLUSIVE); if (VN_IS_DOOMED(dp)) { vput(dp); error = ENOENT; goto errout; } } SDT_PROBE4(vfs, namei, lookup, return, 0, ndp->ni_vp, false, ndp); return (0); errout: SDT_PROBE4(vfs, namei, lookup, return, error, NULL, false, ndp); namei_cleanup_cnp(cnp); return (error); } static int __noinline namei_follow_link(struct nameidata *ndp) { char *cp; struct iovec aiov; struct uio auio; struct componentname *cnp; struct thread *td; int error, linklen; error = 0; cnp = &ndp->ni_cnd; td = curthread; if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { error = ELOOP; goto out; } #ifdef MAC if ((cnp->cn_flags & NOMACCHECK) == 0) { error = mac_vnode_check_readlink(td->td_ucred, ndp->ni_vp); if (error != 0) goto out; } #endif if (ndp->ni_pathlen > 1) cp = uma_zalloc(namei_zone, M_WAITOK); else cp = cnp->cn_pnbuf; aiov.iov_base = cp; aiov.iov_len = MAXPATHLEN; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_SYSSPACE; auio.uio_td = td; auio.uio_resid = MAXPATHLEN; error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); if (error != 0) { if (ndp->ni_pathlen > 1) uma_zfree(namei_zone, cp); goto out; } linklen = MAXPATHLEN - auio.uio_resid; if (linklen == 0) { if (ndp->ni_pathlen > 1) uma_zfree(namei_zone, cp); error = ENOENT; goto out; } if (linklen + ndp->ni_pathlen > MAXPATHLEN) { if (ndp->ni_pathlen > 1) uma_zfree(namei_zone, cp); error = ENAMETOOLONG; goto out; } if (ndp->ni_pathlen > 1) { bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); uma_zfree(namei_zone, cnp->cn_pnbuf); cnp->cn_pnbuf = cp; } else cnp->cn_pnbuf[linklen] = '\0'; ndp->ni_pathlen += linklen; out: return (error); } /* * Convert a pathname into a pointer to a locked vnode. * * The FOLLOW flag is set when symbolic links are to be followed * when they occur at the end of the name translation process. * Symbolic links are always followed for all other pathname * components other than the last. * * The segflg defines whether the name is to be copied from user * space or kernel space. * * Overall outline of namei: * * copy in name * get starting directory * while (!done && !error) { * call lookup to search path. * if symbolic link, massage name in buffer and continue * } */ int namei(struct nameidata *ndp) { struct vnode *dp; /* the directory we are searching */ struct componentname *cnp; struct thread *td; struct pwd *pwd; int error; enum cache_fpl_status status; cnp = &ndp->ni_cnd; td = curthread; #ifdef INVARIANTS KASSERT((ndp->ni_debugflags & NAMEI_DBG_CALLED) == 0, ("%s: repeated call to namei without NDREINIT", __func__)); KASSERT(ndp->ni_debugflags == NAMEI_DBG_INITED, ("%s: bad debugflags %d", __func__, ndp->ni_debugflags)); ndp->ni_debugflags |= NAMEI_DBG_CALLED; if (ndp->ni_startdir != NULL) ndp->ni_debugflags |= NAMEI_DBG_HADSTARTDIR; if (cnp->cn_flags & FAILIFEXISTS) { KASSERT(cnp->cn_nameiop == CREATE, ("%s: FAILIFEXISTS passed for op %d", __func__, cnp->cn_nameiop)); /* * The limitation below is to restrict hairy corner cases. */ KASSERT((cnp->cn_flags & (LOCKPARENT | LOCKLEAF)) == LOCKPARENT, ("%s: FAILIFEXISTS must be passed with LOCKPARENT and without LOCKLEAF", __func__)); } #endif ndp->ni_cnd.cn_cred = td->td_ucred; KASSERT(ndp->ni_resflags == 0, ("%s: garbage in ni_resflags: %x", __func__, ndp->ni_resflags)); KASSERT(cnp->cn_cred && td->td_proc, ("namei: bad cred/proc")); KASSERT((cnp->cn_flags & NAMEI_INTERNAL_FLAGS) == 0, ("namei: unexpected flags: %#jx", (uintmax_t)(cnp->cn_flags & NAMEI_INTERNAL_FLAGS))); if (cnp->cn_flags & NOCACHE) KASSERT(cnp->cn_nameiop != LOOKUP, ("%s: NOCACHE passed with LOOKUP", __func__)); MPASS(ndp->ni_startdir == NULL || ndp->ni_startdir->v_type == VDIR || ndp->ni_startdir->v_type == VBAD); restart: ndp->ni_lcf = 0; ndp->ni_loopcnt = 0; ndp->ni_vp = NULL; error = namei_getpath(ndp); if (__predict_false(error != 0)) { namei_cleanup_cnp(cnp); nameicap_cleanup(ndp, error); SDT_PROBE4(vfs, namei, lookup, return, error, NULL, false, ndp); return (error); } cnp->cn_nameptr = cnp->cn_pnbuf; #ifdef KTRACE if (KTRPOINT(td, KTR_NAMEI)) { ktrnamei(cnp->cn_pnbuf); } #endif TSNAMEI(curthread->td_proc->p_pid, cnp->cn_pnbuf); /* * First try looking up the target without locking any vnodes. * * We may need to start from scratch or pick up where it left off. */ error = cache_fplookup(ndp, &status, &pwd); switch (status) { case CACHE_FPL_STATUS_UNSET: __assert_unreachable(); break; case CACHE_FPL_STATUS_HANDLED: if (error == 0) NDVALIDATE(ndp); else if (__predict_false(pwd->pwd_adir != pwd->pwd_rdir && (cnp->cn_flags & ISRESTARTED) == 0)) { namei_cleanup_cnp(cnp); nameicap_cleanup(ndp, ERESTART); NDRESTART(ndp); goto restart; } return (error); case CACHE_FPL_STATUS_PARTIAL: dp = ndp->ni_startdir; break; case CACHE_FPL_STATUS_DESTROYED: ndp->ni_loopcnt = 0; error = namei_getpath(ndp); if (__predict_false(error != 0)) { namei_cleanup_cnp(cnp); nameicap_cleanup(ndp, error); return (error); } cnp->cn_nameptr = cnp->cn_pnbuf; /* FALLTHROUGH */ case CACHE_FPL_STATUS_ABORTED: MPASS(ndp->ni_lcf == 0); if (*cnp->cn_pnbuf == '\0') { if ((cnp->cn_flags & EMPTYPATH) != 0) { error = namei_emptypath(ndp); nameicap_cleanup(ndp, error); return (error); } namei_cleanup_cnp(cnp); nameicap_cleanup(ndp, ENOENT); SDT_PROBE4(vfs, namei, lookup, return, ENOENT, NULL, false, ndp); return (ENOENT); } error = namei_setup(ndp, &dp, &pwd); if (error != 0) { namei_cleanup_cnp(cnp); nameicap_cleanup(ndp, error); return (error); } break; } /* * Locked lookup. */ for (;;) { ndp->ni_startdir = dp; error = vfs_lookup(ndp); if (error != 0) { uint64_t was_restarted; bool abi_restart; was_restarted = ndp->ni_cnd.cn_flags & ISRESTARTED; abi_restart = pwd->pwd_adir != pwd->pwd_rdir && error == ENOENT && was_restarted == 0; if (error != ERESTART && !abi_restart) goto out; nameicap_cleanup(ndp, error); pwd_drop(pwd); namei_cleanup_cnp(cnp); NDRESET(ndp); if (abi_restart) was_restarted = ISRESTARTED; ndp->ni_cnd.cn_flags |= was_restarted; goto restart; } /* * If not a symbolic link, we're done. */ if ((cnp->cn_flags & ISSYMLINK) == 0) { SDT_PROBE4(vfs, namei, lookup, return, error, ndp->ni_vp, false, ndp); nameicap_cleanup(ndp, 0); pwd_drop(pwd); NDVALIDATE(ndp); return (0); } error = namei_follow_link(ndp); if (error != 0) break; vput(ndp->ni_vp); dp = ndp->ni_dvp; /* * Check if root directory should replace current directory. */ cnp->cn_nameptr = cnp->cn_pnbuf; if (*(cnp->cn_nameptr) == '/') { /* * Reset the lookup to start from the real root without * origin path name reloading. */ if (__predict_false(ndp->ni_rootdir != pwd->pwd_rdir)) { cnp->cn_flags |= ISRESTARTED; ndp->ni_rootdir = pwd->pwd_rdir; } vrele(dp); error = namei_handle_root(ndp, &dp); if (error != 0) goto out; } } vput(ndp->ni_vp); ndp->ni_vp = NULL; vrele(ndp->ni_dvp); out: MPASS(error != 0 && error != ERESTART); SDT_PROBE4(vfs, namei, lookup, return, error, NULL, false, ndp); namei_cleanup_cnp(cnp); nameicap_cleanup(ndp, error); pwd_drop(pwd); return (error); } static int enforce_lkflags(struct mount *mp, int lkflags) { if (mp == NULL || ((lkflags & LK_SHARED) && !(mp->mnt_kern_flag & MNTK_LOOKUP_SHARED))) { lkflags &= ~LK_SHARED; lkflags |= LK_EXCLUSIVE; } lkflags |= LK_NODDLKTREAT; return (lkflags); } static __inline int needs_exclusive_leaf(struct mount *mp, int flags) { /* * Intermediate nodes can use shared locks, we only need to * force an exclusive lock for leaf nodes. */ if ((flags & (ISLASTCN | LOCKLEAF)) != (ISLASTCN | LOCKLEAF)) return (0); /* Always use exclusive locks if LOCKSHARED isn't set. */ if (!(flags & LOCKSHARED)) return (1); /* * For lookups during open(), if the mount point supports * extended shared operations, then use a shared lock for the * leaf node, otherwise use an exclusive lock. */ if ((flags & ISOPEN) != 0) return (!MNT_EXTENDED_SHARED(mp)); /* * Lookup requests outside of open() that specify LOCKSHARED * only need a shared lock on the leaf vnode. */ return (0); } /* * Various filesystems expect to be able to copy a name component with length * bounded by NAME_MAX into a directory entry buffer of size MAXNAMLEN. Make * sure that these are the same size. */ _Static_assert(MAXNAMLEN == NAME_MAX, "MAXNAMLEN and NAME_MAX have different values"); static int __noinline vfs_lookup_degenerate(struct nameidata *ndp, struct vnode *dp, int wantparent) { struct componentname *cnp; struct mount *mp; int error; cnp = &ndp->ni_cnd; cnp->cn_flags |= ISLASTCN; mp = atomic_load_ptr(&dp->v_mount); if (needs_exclusive_leaf(mp, cnp->cn_flags)) { cnp->cn_lkflags &= ~LK_SHARED; cnp->cn_lkflags |= LK_EXCLUSIVE; } vn_lock(dp, enforce_lkflags(mp, cnp->cn_lkflags | LK_RETRY)); if (dp->v_type != VDIR) { error = ENOTDIR; goto bad; } if (cnp->cn_nameiop != LOOKUP) { error = EISDIR; goto bad; } if (wantparent) { ndp->ni_dvp = dp; - VREF(dp); + vref(dp); } ndp->ni_vp = dp; cnp->cn_namelen = 0; if (cnp->cn_flags & AUDITVNODE1) AUDIT_ARG_VNODE1(dp); else if (cnp->cn_flags & AUDITVNODE2) AUDIT_ARG_VNODE2(dp); if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) VOP_UNLOCK(dp); return (0); bad: VOP_UNLOCK(dp); return (error); } struct nameidata * vfs_lookup_nameidata(struct componentname *cnp) { if ((cnp->cn_flags & NAMEILOOKUP) == 0) return (NULL); return (__containerof(cnp, struct nameidata, ni_cnd)); } /* * Would a dotdot lookup relative to dvp cause this lookup to cross a jail or * chroot boundary? */ bool vfs_lookup_isroot(struct nameidata *ndp, struct vnode *dvp) { for (struct prison *pr = ndp->ni_cnd.cn_cred->cr_prison; pr != NULL; pr = pr->pr_parent) { if (dvp == pr->pr_root) return (true); } return (dvp == ndp->ni_rootdir || dvp == ndp->ni_topdir || dvp == rootvnode); } /* * FAILIFEXISTS handling. * * XXX namei called with LOCKPARENT but not LOCKLEAF has the strange * behaviour of leaving the vnode unlocked if the target is the same * vnode as the parent. */ static int __noinline vfs_lookup_failifexists(struct nameidata *ndp) { struct componentname *cnp __diagused; cnp = &ndp->ni_cnd; MPASS((cnp->cn_flags & ISSYMLINK) == 0); if (ndp->ni_vp == ndp->ni_dvp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); vrele(ndp->ni_vp); ndp->ni_dvp = NULL; ndp->ni_vp = NULL; NDFREE_PNBUF(ndp); return (EEXIST); } static int __noinline vfs_lookup_cross_mount(struct nameidata *ndp) { struct componentname *cnp; struct mount *mp; struct vnode *dp, *tdp; int error, crosslkflags; bool crosslock; cnp = &ndp->ni_cnd; dp = ndp->ni_vp; /* * The vnode has been mounted on, find the root of the mounted * filesystem. */ do { mp = dp->v_mountedhere; ASSERT_VOP_LOCKED(dp, __func__); VNPASS((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0 && mp != NULL, dp); crosslock = (dp->v_vflag & VV_CROSSLOCK) != 0; crosslkflags = enforce_lkflags(mp, cnp->cn_lkflags); if (__predict_false(crosslock)) { /* * We are going to be holding the vnode lock, which * in this case is shared by the root vnode of the * filesystem mounted at mp, across the call to * VFS_ROOT(). Make the situation clear to the * filesystem by passing LK_CANRECURSE if the * lock is held exclusive, or by clearinng * LK_NODDLKTREAT to allow recursion on the shared * lock in the presence of an exclusive waiter. */ if (VOP_ISLOCKED(dp) == LK_EXCLUSIVE) { crosslkflags &= ~LK_SHARED; crosslkflags |= LK_EXCLUSIVE | LK_CANRECURSE; } else if ((crosslkflags & LK_EXCLUSIVE) != 0) { error = vn_lock(dp, LK_UPGRADE); if (error != 0) { MPASS(error == ENOENT); vrele(dp); if (dp != ndp->ni_dvp) vput(ndp->ni_dvp); else vrele(ndp->ni_dvp); break; } if (dp->v_mountedhere != mp) { /* * Note that we rely on the * VIRF_MOUNTPOINT loop condition to * ensure we stop iterating if dp is * no longer a mountpoint at all. */ continue; } } else crosslkflags &= ~LK_NODDLKTREAT; } if (vfs_busy(mp, 0) != 0) continue; if (__predict_true(!crosslock)) vput(dp); if (dp != ndp->ni_dvp) vput(ndp->ni_dvp); else vrele(ndp->ni_dvp); vrefact(vp_crossmp); ndp->ni_dvp = vp_crossmp; error = VFS_ROOT(mp, crosslkflags, &tdp); vfs_unbusy(mp); if (__predict_false(crosslock)) vput(dp); if (vn_lock(vp_crossmp, LK_SHARED | LK_NOWAIT)) panic("vp_crossmp exclusively locked or reclaimed"); if (error != 0) break; ndp->ni_vp = dp = tdp; } while ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0); return (error); } /* * Search a pathname. * This is a very central and rather complicated routine. * * The pathname is pointed to by cn_nameptr and is of length ni_pathlen. * The starting directory is taken from ni_startdir. The pathname is * descended until done, or a symbolic link is encountered. The cn_flags * has ISLASTCN or'ed if the path is completed or ISSYMLINK or'ed if a * symbolic link needing interpretation is encountered. * * The cn_nameiop is LOOKUP, CREATE, RENAME, or DELETE depending on * whether the name is to be looked up, created, renamed, or deleted. * When CREATE, RENAME, or DELETE is specified, information usable in * creating, renaming, or deleting a directory entry may be calculated. * If cn_flags has LOCKPARENT or'ed into it, the parent directory is returned * locked. If it has WANTPARENT or'ed into it, the parent directory is * returned unlocked. Otherwise the parent directory is not returned. If * the target of the pathname exists and LOCKLEAF is or'ed into the cn_flags * the target is returned locked, otherwise it is returned unlocked. * * Overall outline of lookup: * * handle degenerate case where name is null string * * dirloop: * identify next component of name at ndp->ni_cnd.cn_nameptr * handle .. special cases related to capabilities, chroot, jail * if .. and crossing mount points and on mounted filesys, find parent * call VOP_LOOKUP routine for next component name * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set * component vnode returned in ni_vp (if it exists), locked. * if result vnode is mounted on and crossing mount points, * find mounted on vnode * if more components of name, do next level at dirloop * if VOP_LOOKUP returns ERELOOKUP, repeat the same level at dirloop * return the answer in ni_vp, locked if LOCKLEAF set * if LOCKPARENT set, return locked parent in ni_dvp * if WANTPARENT set, return unlocked parent in ni_dvp */ int vfs_lookup(struct nameidata *ndp) { char *cp; /* pointer into pathname argument */ char *prev_ni_next; /* saved ndp->ni_next */ char *nulchar; /* location of '\0' in cn_pnbuf */ char *lastchar; /* location of the last character */ struct vnode *dp = NULL; /* the directory we are searching */ struct vnode *tdp; /* saved dp */ size_t prev_ni_pathlen; /* saved ndp->ni_pathlen */ int docache; /* == 0 do not cache last component */ int wantparent; /* 1 => wantparent or lockparent flag */ int rdonly; /* lookup read-only flag bit */ int error = 0; int relookup = 0; /* do not consume the path component */ struct componentname *cnp = &ndp->ni_cnd; int lkflags_save; int ni_dvp_unlocked; /* * Setup: break out flag bits into variables. */ ni_dvp_unlocked = 0; wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); KASSERT(cnp->cn_nameiop == LOOKUP || wantparent, ("CREATE, DELETE, RENAME require LOCKPARENT or WANTPARENT.")); /* * When set to zero, docache causes the last component of the * pathname to be deleted from the cache and the full lookup * of the name to be done (via VOP_CACHEDLOOKUP()). Often * filesystems need some pre-computed values that are made * during the full lookup, for instance UFS sets dp->i_offset. * * The docache variable is set to zero when requested by the * NOCACHE flag and for all modifying operations except CREATE. */ docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; if (cnp->cn_nameiop == DELETE || (wantparent && cnp->cn_nameiop != CREATE && cnp->cn_nameiop != LOOKUP)) docache = 0; rdonly = cnp->cn_flags & RDONLY; cnp->cn_flags &= ~ISSYMLINK; ndp->ni_dvp = NULL; cnp->cn_lkflags = LK_SHARED; dp = ndp->ni_startdir; ndp->ni_startdir = NULL; /* * Leading slashes, if any, are supposed to be skipped by the caller. */ MPASS(cnp->cn_nameptr[0] != '/'); /* * Check for degenerate name (e.g. / or "") which is a way of talking * about a directory, e.g. like "/." or ".". */ if (__predict_false(cnp->cn_nameptr[0] == '\0')) { error = vfs_lookup_degenerate(ndp, dp, wantparent); if (error == 0) goto success_right_lock; goto bad_unlocked; } /* * Nul-out trailing slashes (e.g., "foo///" -> "foo"). * * This must be done before VOP_LOOKUP() because some fs's don't know * about trailing slashes. Remember if there were trailing slashes to * handle symlinks, existing non-directories and non-existing files * that won't be directories specially later. */ MPASS(ndp->ni_pathlen >= 2); lastchar = &cnp->cn_nameptr[ndp->ni_pathlen - 2]; if (*lastchar == '/') { while (lastchar >= cnp->cn_pnbuf) { *lastchar = '\0'; lastchar--; ndp->ni_pathlen--; if (*lastchar != '/') { break; } } cnp->cn_flags |= TRAILINGSLASH; } /* * We use shared locks until we hit the parent of the last cn then * we adjust based on the requesting flags. */ vn_lock(dp, enforce_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY)); dirloop: /* * Search a new directory. * * The last component of the filename is left accessible via * cnp->cn_nameptr. It has to be freed with a call to NDFREE*. * * Store / as a temporary sentinel so that we only have one character * to test for. Pathnames tend to be short so this should not be * resulting in cache misses. */ nulchar = &cnp->cn_nameptr[ndp->ni_pathlen - 1]; KASSERT(*nulchar == '\0', ("%s: expected nul at %p; string [%s]\n", __func__, nulchar, cnp->cn_pnbuf)); *nulchar = '/'; for (cp = cnp->cn_nameptr; *cp != '/'; cp++) { KASSERT(*cp != '\0', ("%s: encountered unexpected nul; string [%s]\n", __func__, cnp->cn_nameptr)); continue; } *nulchar = '\0'; cnp->cn_namelen = cp - cnp->cn_nameptr; if (__predict_false(cnp->cn_namelen > NAME_MAX)) { error = ENAMETOOLONG; goto bad; } prev_ni_pathlen = ndp->ni_pathlen; ndp->ni_pathlen -= cnp->cn_namelen; KASSERT(ndp->ni_pathlen <= PATH_MAX, ("%s: ni_pathlen underflow to %zd\n", __func__, ndp->ni_pathlen)); prev_ni_next = ndp->ni_next; ndp->ni_next = cp; /* * Something else should be clearing this. */ cnp->cn_flags &= ~(ISDOTDOT|ISLASTCN); cnp->cn_flags |= MAKEENTRY; if (*cp == '\0' && docache == 0) cnp->cn_flags &= ~MAKEENTRY; if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') cnp->cn_flags |= ISDOTDOT; if (*ndp->ni_next == 0) { cnp->cn_flags |= ISLASTCN; if (__predict_false(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.' && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))) { error = EINVAL; goto bad; } } error = nameicap_tracker_add(ndp, dp); if (error != 0) goto bad; /* * Make sure degenerate names don't get here, their handling was * previously found in this spot. */ MPASS(cnp->cn_nameptr[0] != '\0'); /* * Handle "..": five special cases. * 0. If doing a capability lookup and lookup_cap_dotdot is * disabled, return ENOTCAPABLE. * 1. Return an error if this is the last component of * the name and the operation is DELETE or RENAME. * 2. If at root directory (e.g. after chroot) * or at absolute root directory * then ignore it so can't get out. * 3. If this vnode is the root of a mounted * filesystem, then replace it with the * vnode which was mounted on so we take the * .. in the other filesystem. * 4. If the vnode is the top directory of * the jail or chroot, don't let them out. * 5. If doing a capability lookup and lookup_cap_dotdot is * enabled, return ENOTCAPABLE if the lookup would escape * from the initial file descriptor directory. */ if (cnp->cn_flags & ISDOTDOT) { if (__predict_false((ndp->ni_lcf & (NI_LCF_STRICTREL_KTR | NI_LCF_CAP_DOTDOT_KTR)) == NI_LCF_STRICTREL_KTR)) NI_CAP_VIOLATION(ndp, cnp->cn_pnbuf); if (__predict_false((ndp->ni_lcf & (NI_LCF_STRICTREL | NI_LCF_CAP_DOTDOT)) == NI_LCF_STRICTREL)) { error = ENOTCAPABLE; goto bad; } if ((cnp->cn_flags & ISLASTCN) != 0 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { error = EINVAL; goto bad; } for (;;) { bool isroot; isroot = vfs_lookup_isroot(ndp, dp); if (__predict_false(isroot && (ndp->ni_lcf & (NI_LCF_STRICTREL | NI_LCF_STRICTREL_KTR)) != 0)) { if ((ndp->ni_lcf & NI_LCF_STRICTREL_KTR) != 0) NI_CAP_VIOLATION(ndp, cnp->cn_pnbuf); if ((ndp->ni_lcf & NI_LCF_STRICTREL) != 0) { error = ENOTCAPABLE; goto bad; } } if (isroot || ((dp->v_vflag & VV_ROOT) != 0 && (cnp->cn_flags & NOCROSSMOUNT) != 0)) { ndp->ni_dvp = dp; ndp->ni_vp = dp; - VREF(dp); + vref(dp); goto nextname; } if ((dp->v_vflag & VV_ROOT) == 0) break; if (VN_IS_DOOMED(dp)) { /* forced unmount */ error = ENOENT; goto bad; } tdp = dp; dp = dp->v_mount->mnt_vnodecovered; - VREF(dp); + vref(dp); vput(tdp); vn_lock(dp, enforce_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY)); } } /* * We now have a segment name to search for, and a directory to search. */ unionlookup: #ifdef MAC error = mac_vnode_check_lookup(cnp->cn_cred, dp, cnp); if (__predict_false(error)) goto bad; #endif ndp->ni_dvp = dp; ndp->ni_vp = NULL; ASSERT_VOP_LOCKED(dp, "lookup"); /* * If we have a shared lock we may need to upgrade the lock for the * last operation. */ if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) && dp != vp_crossmp && VOP_ISLOCKED(dp) == LK_SHARED) vn_lock(dp, LK_UPGRADE|LK_RETRY); if (VN_IS_DOOMED(dp)) { error = ENOENT; goto bad; } /* * If we're looking up the last component and we need an exclusive * lock, adjust our lkflags. */ if (needs_exclusive_leaf(dp->v_mount, cnp->cn_flags)) cnp->cn_lkflags = LK_EXCLUSIVE; lkflags_save = cnp->cn_lkflags; cnp->cn_lkflags = enforce_lkflags(dp->v_mount, cnp->cn_lkflags); error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp); cnp->cn_lkflags = lkflags_save; if (error != 0) { KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); if ((error == ENOENT) && (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) && (dp->v_mount->mnt_flag & MNT_UNION)) { tdp = dp; dp = dp->v_mount->mnt_vnodecovered; - VREF(dp); + vref(dp); vput(tdp); vn_lock(dp, enforce_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY)); error = nameicap_tracker_add(ndp, dp); if (error != 0) goto bad; goto unionlookup; } if (error == ERELOOKUP) { vref(dp); ndp->ni_vp = dp; error = 0; relookup = 1; goto good; } if (error != EJUSTRETURN) goto bad; /* * At this point, we know we're at the end of the * pathname. If creating / renaming, we can consider * allowing the file or directory to be created / renamed, * provided we're not on a read-only filesystem. */ if (rdonly) { error = EROFS; goto bad; } /* trailing slash only allowed for directories */ if ((cnp->cn_flags & TRAILINGSLASH) && !(cnp->cn_flags & WILLBEDIR)) { error = ENOENT; goto bad; } if ((cnp->cn_flags & LOCKPARENT) == 0) VOP_UNLOCK(dp); /* * We return with ni_vp NULL to indicate that the entry * doesn't currently exist, leaving a pointer to the * (possibly locked) directory vnode in ndp->ni_dvp. */ goto success; } good: dp = ndp->ni_vp; /* * Check for symbolic link */ if ((dp->v_type == VLNK) && ((cnp->cn_flags & FOLLOW) || (cnp->cn_flags & TRAILINGSLASH) || *ndp->ni_next == '/')) { cnp->cn_flags |= ISSYMLINK; if (VN_IS_DOOMED(dp)) { /* * We can't know whether the directory was mounted with * NOSYMFOLLOW, so we can't follow safely. */ error = ENOENT; goto bad2; } if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { error = EACCES; goto bad2; } /* * Symlink code always expects an unlocked dvp. */ if (ndp->ni_dvp != ndp->ni_vp) { VOP_UNLOCK(ndp->ni_dvp); ni_dvp_unlocked = 1; } goto success; } if ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0 && (cnp->cn_flags & NOCROSSMOUNT) == 0) { error = vfs_lookup_cross_mount(ndp); if (error != 0) goto bad_unlocked; /* * FALLTHROUGH to nextname */ dp = ndp->ni_vp; } nextname: /* * Not a symbolic link that we will follow. Continue with the * next component if there is any; otherwise, we're done. */ KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next == '/', ("lookup: invalid path state.")); if (relookup) { relookup = 0; ndp->ni_pathlen = prev_ni_pathlen; ndp->ni_next = prev_ni_next; if (ndp->ni_dvp != dp) vput(ndp->ni_dvp); else vrele(ndp->ni_dvp); goto dirloop; } if (cnp->cn_flags & ISDOTDOT) { error = nameicap_check_dotdot(ndp, ndp->ni_dvp); if (error != 0) goto bad2; } if (*ndp->ni_next == '/') { cnp->cn_nameptr = ndp->ni_next; while (*cnp->cn_nameptr == '/') { cnp->cn_nameptr++; ndp->ni_pathlen--; } if (ndp->ni_dvp != dp) vput(ndp->ni_dvp); else vrele(ndp->ni_dvp); goto dirloop; } /* * If we're processing a path with a trailing slash, * check that the end result is a directory. */ if ((cnp->cn_flags & TRAILINGSLASH) && dp->v_type != VDIR) { error = ENOTDIR; goto bad2; } /* * Disallow directory write attempts on read-only filesystems. */ if (rdonly && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { error = EROFS; goto bad2; } if (!wantparent) { ni_dvp_unlocked = 2; if (ndp->ni_dvp != dp) vput(ndp->ni_dvp); else vrele(ndp->ni_dvp); } else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp) { VOP_UNLOCK(ndp->ni_dvp); ni_dvp_unlocked = 1; } if (cnp->cn_flags & AUDITVNODE1) AUDIT_ARG_VNODE1(dp); else if (cnp->cn_flags & AUDITVNODE2) AUDIT_ARG_VNODE2(dp); if ((cnp->cn_flags & LOCKLEAF) == 0) VOP_UNLOCK(dp); success: /* * FIXME: for lookups which only cross a mount point to fetch the * root vnode, ni_dvp will be set to vp_crossmp. This can be a problem * if either WANTPARENT or LOCKPARENT is set. */ /* * Because of shared lookup we may have the vnode shared locked, but * the caller may want it to be exclusively locked. */ if (needs_exclusive_leaf(dp->v_mount, cnp->cn_flags) && VOP_ISLOCKED(dp) != LK_EXCLUSIVE) { vn_lock(dp, LK_UPGRADE | LK_RETRY); if (VN_IS_DOOMED(dp)) { error = ENOENT; goto bad2; } } success_right_lock: if (ndp->ni_vp != NULL) { if ((cnp->cn_flags & ISDOTDOT) == 0) { error = nameicap_tracker_add(ndp, ndp->ni_vp); if (error != 0) goto bad2; } if ((cnp->cn_flags & (FAILIFEXISTS | ISSYMLINK)) == FAILIFEXISTS) return (vfs_lookup_failifexists(ndp)); } return (0); bad2: if (ni_dvp_unlocked != 2) { if (dp != ndp->ni_dvp && !ni_dvp_unlocked) vput(ndp->ni_dvp); else vrele(ndp->ni_dvp); } bad: vput(dp); bad_unlocked: ndp->ni_vp = NULL; return (error); } /* * relookup - lookup a path name component * Used by lookup to re-acquire things. */ int vfs_relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, bool refstart) { struct vnode *dp = NULL; /* the directory we are searching */ int rdonly; /* lookup read-only flag bit */ int error = 0; KASSERT(cnp->cn_flags & ISLASTCN, ("relookup: Not given last component.")); /* * Setup: break out flag bits into variables. */ KASSERT((cnp->cn_flags & (LOCKPARENT | WANTPARENT)) != 0, ("relookup: parent not wanted")); rdonly = cnp->cn_flags & RDONLY; cnp->cn_flags &= ~ISSYMLINK; dp = dvp; cnp->cn_lkflags = LK_EXCLUSIVE; vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); /* * Search a new directory. * * See a comment in vfs_lookup for cnp->cn_nameptr. * * Check for "" which represents the root directory after slash * removal. */ if (cnp->cn_nameptr[0] == '\0') { /* * Support only LOOKUP for "/" because lookup() * can't succeed for CREATE, DELETE and RENAME. */ KASSERT(cnp->cn_nameiop == LOOKUP, ("nameiop must be LOOKUP")); KASSERT(dp->v_type == VDIR, ("dp is not a directory")); if (!(cnp->cn_flags & LOCKLEAF)) VOP_UNLOCK(dp); *vpp = dp; /* XXX This should probably move to the top of function. */ if (refstart) panic("lookup: SAVESTART"); return (0); } if (cnp->cn_flags & ISDOTDOT) panic ("relookup: lookup on dot-dot"); /* * We now have a segment name to search for, and a directory to search. */ if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { KASSERT(*vpp == NULL, ("leaf should be empty")); if (error != EJUSTRETURN) goto bad; /* * If creating and at end of pathname, then can consider * allowing file to be created. */ if (rdonly) { error = EROFS; goto bad; } /* ASSERT(dvp == ndp->ni_startdir) */ if (refstart) - VREF(dvp); + vref(dvp); if ((cnp->cn_flags & LOCKPARENT) == 0) VOP_UNLOCK(dp); /* * We return with ni_vp NULL to indicate that the entry * doesn't currently exist, leaving a pointer to the * (possibly locked) directory vnode in ndp->ni_dvp. */ return (0); } dp = *vpp; /* * Disallow directory write attempts on read-only filesystems. */ if (rdonly && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { if (dvp == dp) vrele(dvp); else vput(dvp); error = EROFS; goto bad; } /* * Set the parent lock/ref state to the requested state. */ if ((cnp->cn_flags & LOCKPARENT) == 0 && dvp != dp) VOP_UNLOCK(dvp); /* * Check for symbolic link */ KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW), ("relookup: symlink found.\n")); /* ASSERT(dvp == ndp->ni_startdir) */ if (refstart) - VREF(dvp); + vref(dvp); if ((cnp->cn_flags & LOCKLEAF) == 0) VOP_UNLOCK(dp); return (0); bad: vput(dp); *vpp = NULL; return (error); } #ifdef INVARIANTS /* * Validate the final state of ndp after the lookup. */ static void NDVALIDATE_impl(struct nameidata *ndp, int line) { struct componentname *cnp; cnp = &ndp->ni_cnd; if (cnp->cn_pnbuf == NULL) panic("%s: got no buf! called from %d", __func__, line); } #endif diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index ec1aad59c6ee..9e1275359715 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,5238 +1,5238 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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_capsicum.h" #include "opt_ktrace.h" #define EXTERR_CATEGORY EXTERR_CAT_VFSSYSCALL #include #ifdef COMPAT_FREEBSD11 #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KTRACE #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MALLOC_DEFINE(M_FADVISE, "fadvise", "posix_fadvise(2) information"); static int kern_chflagsat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, u_long flags, int atflag); static int setfflags(struct thread *td, struct vnode *, u_long); static int getutimes(const struct timeval *, enum uio_seg, struct timespec *); static int getutimens(const struct timespec *, enum uio_seg, struct timespec *, int *); static int setutimes(struct thread *td, struct vnode *, const struct timespec *, int, int); static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred, struct thread *td); static int kern_fhlinkat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, fhandle_t *fhp); static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg, size_t count, struct thread *td); static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path, enum uio_seg segflag); uint64_t at2cnpflags(u_int at_flags, u_int mask) { uint64_t res; MPASS((at_flags & (AT_SYMLINK_FOLLOW | AT_SYMLINK_NOFOLLOW)) != (AT_SYMLINK_FOLLOW | AT_SYMLINK_NOFOLLOW)); res = 0; at_flags &= mask; if ((at_flags & AT_RESOLVE_BENEATH) != 0) res |= RBENEATH; if ((at_flags & AT_SYMLINK_FOLLOW) != 0) res |= FOLLOW; /* NOFOLLOW is pseudo flag */ if ((mask & AT_SYMLINK_NOFOLLOW) != 0) { res |= (at_flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : FOLLOW; } if ((mask & AT_EMPTY_PATH) != 0 && (at_flags & AT_EMPTY_PATH) != 0) res |= EMPTYPATH; return (res); } int kern_sync(struct thread *td) { struct mount *mp, *nmp; int save; mtx_lock(&mountlist_mtx); for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK)) { nmp = TAILQ_NEXT(mp, mnt_list); continue; } if ((mp->mnt_flag & MNT_RDONLY) == 0 && vn_start_write(NULL, &mp, V_NOWAIT) == 0) { save = curthread_pflags_set(TDP_SYNCIO); vfs_periodic(mp, MNT_NOWAIT); VFS_SYNC(mp, MNT_NOWAIT); curthread_pflags_restore(save); vn_finished_write(mp); } mtx_lock(&mountlist_mtx); nmp = TAILQ_NEXT(mp, mnt_list); vfs_unbusy(mp); } mtx_unlock(&mountlist_mtx); return (0); } /* * Sync each mounted filesystem. */ #ifndef _SYS_SYSPROTO_H_ struct sync_args { int dummy; }; #endif /* ARGSUSED */ int sys_sync(struct thread *td, struct sync_args *uap) { return (kern_sync(td)); } /* * Change filesystem quotas. */ #ifndef _SYS_SYSPROTO_H_ struct quotactl_args { char *path; int cmd; int uid; caddr_t arg; }; #endif int sys_quotactl(struct thread *td, struct quotactl_args *uap) { struct mount *mp; struct nameidata nd; int error; bool mp_busy; AUDIT_ARG_CMD(uap->cmd); AUDIT_ARG_UID(uap->uid); if (!prison_allow(td->td_ucred, PR_ALLOW_QUOTAS)) return (EPERM); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, uap->path); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); mp = nd.ni_vp->v_mount; vfs_ref(mp); vput(nd.ni_vp); error = vfs_busy(mp, 0); if (error != 0) { vfs_rel(mp); return (error); } mp_busy = true; error = VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, &mp_busy); /* * Since quota on/off operations typically need to open quota * files, the implementation may need to unbusy the mount point * before calling into namei. Otherwise, unmount might be * started between two vfs_busy() invocations (first is ours, * second is from mount point cross-walk code in lookup()), * causing deadlock. * * Avoid unbusying mp if the implementation indicates it has * already done so. */ if (mp_busy) vfs_unbusy(mp); vfs_rel(mp); return (error); } /* * Used by statfs conversion routines to scale the block size up if * necessary so that all of the block counts are <= 'max_size'. Note * that 'max_size' should be a bitmask, i.e. 2^n - 1 for some non-zero * value of 'n'. */ void statfs_scale_blocks(struct statfs *sf, long max_size) { uint64_t count; int shift; KASSERT(powerof2(max_size + 1), ("%s: invalid max_size", __func__)); /* * Attempt to scale the block counts to give a more accurate * overview to userland of the ratio of free space to used * space. To do this, find the largest block count and compute * a divisor that lets it fit into a signed integer <= max_size. */ if (sf->f_bavail < 0) count = -sf->f_bavail; else count = sf->f_bavail; count = MAX(sf->f_blocks, MAX(sf->f_bfree, count)); if (count <= max_size) return; count >>= flsl(max_size); shift = 0; while (count > 0) { shift++; count >>=1; } sf->f_bsize <<= shift; sf->f_blocks >>= shift; sf->f_bfree >>= shift; sf->f_bavail >>= shift; } static int kern_do_statfs(struct thread *td, struct mount *mp, struct statfs *buf) { int error; if (mp == NULL) return (EBADF); error = vfs_busy(mp, 0); vfs_rel(mp); if (error != 0) return (error); #ifdef MAC error = mac_mount_check_stat(td->td_ucred, mp); if (error != 0) goto out; #endif error = VFS_STATFS(mp, buf); if (error != 0) goto out; if (priv_check_cred_vfs_generation(td->td_ucred)) { buf->f_fsid.val[0] = buf->f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, buf); } out: vfs_unbusy(mp); return (error); } /* * Get filesystem statistics. */ #ifndef _SYS_SYSPROTO_H_ struct statfs_args { char *path; struct statfs *buf; }; #endif int sys_statfs(struct thread *td, struct statfs_args *uap) { struct statfs *sfp; int error; sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp); if (error == 0) error = copyout(sfp, uap->buf, sizeof(struct statfs)); free(sfp, M_STATFS); return (error); } int kern_statfs(struct thread *td, const char *path, enum uio_seg pathseg, struct statfs *buf) { struct mount *mp; struct nameidata nd; int error; NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path); error = namei(&nd); if (error != 0) return (error); NDFREE_PNBUF(&nd); mp = vfs_ref_from_vp(nd.ni_vp); vrele(nd.ni_vp); return (kern_do_statfs(td, mp, buf)); } /* * Get filesystem statistics. */ #ifndef _SYS_SYSPROTO_H_ struct fstatfs_args { int fd; struct statfs *buf; }; #endif int sys_fstatfs(struct thread *td, struct fstatfs_args *uap) { struct statfs *sfp; int error; sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_fstatfs(td, uap->fd, sfp); if (error == 0) error = copyout(sfp, uap->buf, sizeof(struct statfs)); free(sfp, M_STATFS); return (error); } int kern_fstatfs(struct thread *td, int fd, struct statfs *buf) { struct file *fp; struct mount *mp; struct vnode *vp; int error; AUDIT_ARG_FD(fd); error = getvnode_path(td, fd, &cap_fstatfs_rights, NULL, &fp); if (error != 0) return (error); vp = fp->f_vnode; #ifdef AUDIT if (AUDITING_TD(td)) { vn_lock(vp, LK_SHARED | LK_RETRY); AUDIT_ARG_VNODE1(vp); VOP_UNLOCK(vp); } #endif mp = vfs_ref_from_vp(vp); fdrop(fp, td); return (kern_do_statfs(td, mp, buf)); } /* * Get statistics on all filesystems. */ #ifndef _SYS_SYSPROTO_H_ struct getfsstat_args { struct statfs *buf; long bufsize; int mode; }; #endif int sys_getfsstat(struct thread *td, struct getfsstat_args *uap) { size_t count; int error; if (uap->bufsize < 0 || uap->bufsize > SIZE_MAX) return (EINVAL); error = kern_getfsstat(td, &uap->buf, uap->bufsize, &count, UIO_USERSPACE, uap->mode); if (error == 0) td->td_retval[0] = count; return (error); } /* * If (bufsize > 0 && bufseg == UIO_SYSSPACE) * The caller is responsible for freeing memory which will be allocated * in '*buf'. */ int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize, size_t *countp, enum uio_seg bufseg, int mode) { struct mount *mp, *nmp; struct statfs *sfsp, *sp, *sptmp, *tofree; size_t count, maxcount; int error; switch (mode) { case MNT_WAIT: case MNT_NOWAIT: break; default: if (bufseg == UIO_SYSSPACE) *buf = NULL; return (EINVAL); } restart: maxcount = bufsize / sizeof(struct statfs); if (bufsize == 0) { sfsp = NULL; tofree = NULL; } else if (bufseg == UIO_USERSPACE) { sfsp = *buf; tofree = NULL; } else /* if (bufseg == UIO_SYSSPACE) */ { count = 0; mtx_lock(&mountlist_mtx); TAILQ_FOREACH(mp, &mountlist, mnt_list) { count++; } mtx_unlock(&mountlist_mtx); if (maxcount > count) maxcount = count; tofree = sfsp = *buf = malloc(maxcount * sizeof(struct statfs), M_STATFS, M_WAITOK); } count = 0; /* * If there is no target buffer they only want the count. * * This could be TAILQ_FOREACH but it is open-coded to match the original * code below. */ if (sfsp == NULL) { mtx_lock(&mountlist_mtx); for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { if (prison_canseemount(td->td_ucred, mp) != 0) { nmp = TAILQ_NEXT(mp, mnt_list); continue; } #ifdef MAC if (mac_mount_check_stat(td->td_ucred, mp) != 0) { nmp = TAILQ_NEXT(mp, mnt_list); continue; } #endif count++; nmp = TAILQ_NEXT(mp, mnt_list); } mtx_unlock(&mountlist_mtx); *countp = count; return (0); } /* * They want the entire thing. * * Short-circuit the corner case of no room for anything, avoids * relocking below. */ if (maxcount < 1) { goto out; } mtx_lock(&mountlist_mtx); for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { if (prison_canseemount(td->td_ucred, mp) != 0) { nmp = TAILQ_NEXT(mp, mnt_list); continue; } #ifdef MAC if (mac_mount_check_stat(td->td_ucred, mp) != 0) { nmp = TAILQ_NEXT(mp, mnt_list); continue; } #endif if (mode == MNT_WAIT) { if (vfs_busy(mp, MBF_MNTLSTLOCK) != 0) { /* * If vfs_busy() failed, and MBF_NOWAIT * wasn't passed, then the mp is gone. * Furthermore, because of MBF_MNTLSTLOCK, * the mountlist_mtx was dropped. We have * no other choice than to start over. */ mtx_unlock(&mountlist_mtx); free(tofree, M_STATFS); goto restart; } } else { if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK) != 0) { nmp = TAILQ_NEXT(mp, mnt_list); continue; } } sp = &mp->mnt_stat; /* * If MNT_NOWAIT is specified, do not refresh * the fsstat cache. */ if (mode != MNT_NOWAIT) { error = VFS_STATFS(mp, sp); if (error != 0) { mtx_lock(&mountlist_mtx); nmp = TAILQ_NEXT(mp, mnt_list); vfs_unbusy(mp); continue; } } if (priv_check_cred_vfs_generation(td->td_ucred)) { sptmp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); *sptmp = *sp; sptmp->f_fsid.val[0] = sptmp->f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, sptmp); sp = sptmp; } else sptmp = NULL; if (bufseg == UIO_SYSSPACE) { bcopy(sp, sfsp, sizeof(*sp)); free(sptmp, M_STATFS); } else /* if (bufseg == UIO_USERSPACE) */ { error = copyout(sp, sfsp, sizeof(*sp)); free(sptmp, M_STATFS); if (error != 0) { vfs_unbusy(mp); return (error); } } sfsp++; count++; if (count == maxcount) { vfs_unbusy(mp); goto out; } mtx_lock(&mountlist_mtx); nmp = TAILQ_NEXT(mp, mnt_list); vfs_unbusy(mp); } mtx_unlock(&mountlist_mtx); out: *countp = count; return (0); } #ifdef COMPAT_FREEBSD4 /* * Get old format filesystem statistics. */ static void freebsd4_cvtstatfs(struct statfs *, struct ostatfs *); #ifndef _SYS_SYSPROTO_H_ struct freebsd4_statfs_args { char *path; struct ostatfs *buf; }; #endif int freebsd4_statfs(struct thread *td, struct freebsd4_statfs_args *uap) { struct ostatfs osb; struct statfs *sfp; int error; sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp); if (error == 0) { freebsd4_cvtstatfs(sfp, &osb); error = copyout(&osb, uap->buf, sizeof(osb)); } free(sfp, M_STATFS); return (error); } /* * Get filesystem statistics. */ #ifndef _SYS_SYSPROTO_H_ struct freebsd4_fstatfs_args { int fd; struct ostatfs *buf; }; #endif int freebsd4_fstatfs(struct thread *td, struct freebsd4_fstatfs_args *uap) { struct ostatfs osb; struct statfs *sfp; int error; sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_fstatfs(td, uap->fd, sfp); if (error == 0) { freebsd4_cvtstatfs(sfp, &osb); error = copyout(&osb, uap->buf, sizeof(osb)); } free(sfp, M_STATFS); return (error); } /* * Get statistics on all filesystems. */ #ifndef _SYS_SYSPROTO_H_ struct freebsd4_getfsstat_args { struct ostatfs *buf; long bufsize; int mode; }; #endif int freebsd4_getfsstat(struct thread *td, struct freebsd4_getfsstat_args *uap) { struct statfs *buf, *sp; struct ostatfs osb; size_t count, size; int error; if (uap->bufsize < 0) return (EINVAL); count = uap->bufsize / sizeof(struct ostatfs); if (count > SIZE_MAX / sizeof(struct statfs)) return (EINVAL); size = count * sizeof(struct statfs); error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, uap->mode); if (error == 0) td->td_retval[0] = count; if (size != 0) { sp = buf; while (count != 0 && error == 0) { freebsd4_cvtstatfs(sp, &osb); error = copyout(&osb, uap->buf, sizeof(osb)); sp++; uap->buf++; count--; } free(buf, M_STATFS); } return (error); } /* * Implement fstatfs() for (NFS) file handles. */ #ifndef _SYS_SYSPROTO_H_ struct freebsd4_fhstatfs_args { struct fhandle *u_fhp; struct ostatfs *buf; }; #endif int freebsd4_fhstatfs(struct thread *td, struct freebsd4_fhstatfs_args *uap) { struct ostatfs osb; struct statfs *sfp; fhandle_t fh; int error; error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); if (error != 0) return (error); sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_fhstatfs(td, fh, sfp); if (error == 0) { freebsd4_cvtstatfs(sfp, &osb); error = copyout(&osb, uap->buf, sizeof(osb)); } free(sfp, M_STATFS); return (error); } /* * Convert a new format statfs structure to an old format statfs structure. */ static void freebsd4_cvtstatfs(struct statfs *nsp, struct ostatfs *osp) { statfs_scale_blocks(nsp, LONG_MAX); bzero(osp, sizeof(*osp)); osp->f_bsize = nsp->f_bsize; osp->f_iosize = MIN(nsp->f_iosize, LONG_MAX); osp->f_blocks = nsp->f_blocks; osp->f_bfree = nsp->f_bfree; osp->f_bavail = nsp->f_bavail; osp->f_files = MIN(nsp->f_files, LONG_MAX); osp->f_ffree = MIN(nsp->f_ffree, LONG_MAX); osp->f_owner = nsp->f_owner; osp->f_type = nsp->f_type; osp->f_flags = nsp->f_flags; osp->f_syncwrites = MIN(nsp->f_syncwrites, LONG_MAX); osp->f_asyncwrites = MIN(nsp->f_asyncwrites, LONG_MAX); osp->f_syncreads = MIN(nsp->f_syncreads, LONG_MAX); osp->f_asyncreads = MIN(nsp->f_asyncreads, LONG_MAX); strlcpy(osp->f_fstypename, nsp->f_fstypename, MIN(MFSNAMELEN, OMFSNAMELEN)); strlcpy(osp->f_mntonname, nsp->f_mntonname, MIN(MNAMELEN, OMNAMELEN)); strlcpy(osp->f_mntfromname, nsp->f_mntfromname, MIN(MNAMELEN, OMNAMELEN)); osp->f_fsid = nsp->f_fsid; } #endif /* COMPAT_FREEBSD4 */ #if defined(COMPAT_FREEBSD11) /* * Get old format filesystem statistics. */ static void freebsd11_cvtstatfs(struct statfs *, struct freebsd11_statfs *); int freebsd11_statfs(struct thread *td, struct freebsd11_statfs_args *uap) { struct freebsd11_statfs osb; struct statfs *sfp; int error; sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp); if (error == 0) { freebsd11_cvtstatfs(sfp, &osb); error = copyout(&osb, uap->buf, sizeof(osb)); } free(sfp, M_STATFS); return (error); } /* * Get filesystem statistics. */ int freebsd11_fstatfs(struct thread *td, struct freebsd11_fstatfs_args *uap) { struct freebsd11_statfs osb; struct statfs *sfp; int error; sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_fstatfs(td, uap->fd, sfp); if (error == 0) { freebsd11_cvtstatfs(sfp, &osb); error = copyout(&osb, uap->buf, sizeof(osb)); } free(sfp, M_STATFS); return (error); } /* * Get statistics on all filesystems. */ int freebsd11_getfsstat(struct thread *td, struct freebsd11_getfsstat_args *uap) { return (kern_freebsd11_getfsstat(td, uap->buf, uap->bufsize, uap->mode)); } int kern_freebsd11_getfsstat(struct thread *td, struct freebsd11_statfs * ubuf, long bufsize, int mode) { struct freebsd11_statfs osb; struct statfs *buf, *sp; size_t count, size; int error; if (bufsize < 0) return (EINVAL); count = bufsize / sizeof(struct ostatfs); size = count * sizeof(struct statfs); error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, mode); if (error == 0) td->td_retval[0] = count; if (size > 0) { sp = buf; while (count > 0 && error == 0) { freebsd11_cvtstatfs(sp, &osb); error = copyout(&osb, ubuf, sizeof(osb)); sp++; ubuf++; count--; } free(buf, M_STATFS); } return (error); } /* * Implement fstatfs() for (NFS) file handles. */ int freebsd11_fhstatfs(struct thread *td, struct freebsd11_fhstatfs_args *uap) { struct freebsd11_statfs osb; struct statfs *sfp; fhandle_t fh; int error; error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); if (error) return (error); sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_fhstatfs(td, fh, sfp); if (error == 0) { freebsd11_cvtstatfs(sfp, &osb); error = copyout(&osb, uap->buf, sizeof(osb)); } free(sfp, M_STATFS); return (error); } /* * Convert a new format statfs structure to an old format statfs structure. */ static void freebsd11_cvtstatfs(struct statfs *nsp, struct freebsd11_statfs *osp) { bzero(osp, sizeof(*osp)); osp->f_version = FREEBSD11_STATFS_VERSION; osp->f_type = nsp->f_type; osp->f_flags = nsp->f_flags; osp->f_bsize = nsp->f_bsize; osp->f_iosize = nsp->f_iosize; osp->f_blocks = nsp->f_blocks; osp->f_bfree = nsp->f_bfree; osp->f_bavail = nsp->f_bavail; osp->f_files = nsp->f_files; osp->f_ffree = nsp->f_ffree; osp->f_syncwrites = nsp->f_syncwrites; osp->f_asyncwrites = nsp->f_asyncwrites; osp->f_syncreads = nsp->f_syncreads; osp->f_asyncreads = nsp->f_asyncreads; osp->f_namemax = nsp->f_namemax; osp->f_owner = nsp->f_owner; osp->f_fsid = nsp->f_fsid; strlcpy(osp->f_fstypename, nsp->f_fstypename, MIN(MFSNAMELEN, sizeof(osp->f_fstypename))); strlcpy(osp->f_mntonname, nsp->f_mntonname, MIN(MNAMELEN, sizeof(osp->f_mntonname))); strlcpy(osp->f_mntfromname, nsp->f_mntfromname, MIN(MNAMELEN, sizeof(osp->f_mntfromname))); } #endif /* COMPAT_FREEBSD11 */ /* * Change current working directory to a given file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct fchdir_args { int fd; }; #endif int sys_fchdir(struct thread *td, struct fchdir_args *uap) { struct vnode *vp, *tdp; struct mount *mp; struct file *fp; int error; uint8_t fdflags; AUDIT_ARG_FD(uap->fd); error = getvnode_path(td, uap->fd, &cap_fchdir_rights, &fdflags, &fp); if (error != 0) return (error); if ((fdflags & UF_RESOLVE_BENEATH) != 0) { fdrop(fp, td); return (ENOTCAPABLE); } vp = fp->f_vnode; vrefact(vp); fdrop(fp, td); vn_lock(vp, LK_SHARED | LK_RETRY); AUDIT_ARG_VNODE1(vp); error = change_dir(vp, td); while (!error && (mp = vp->v_mountedhere) != NULL) { if (vfs_busy(mp, 0)) continue; error = VFS_ROOT(mp, LK_SHARED, &tdp); vfs_unbusy(mp); if (error != 0) break; vput(vp); vp = tdp; } if (error != 0) { vput(vp); return (error); } VOP_UNLOCK(vp); pwd_chdir(td, vp); return (0); } /* * Change current working directory (``.''). */ #ifndef _SYS_SYSPROTO_H_ struct chdir_args { char *path; }; #endif int sys_chdir(struct thread *td, struct chdir_args *uap) { return (kern_chdir(td, uap->path, UIO_USERSPACE)); } int kern_chdir(struct thread *td, const char *path, enum uio_seg pathseg) { struct nameidata nd; int error; NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path); if ((error = namei(&nd)) != 0) return (error); if ((error = change_dir(nd.ni_vp, td)) != 0) { vput(nd.ni_vp); NDFREE_PNBUF(&nd); return (error); } VOP_UNLOCK(nd.ni_vp); NDFREE_PNBUF(&nd); pwd_chdir(td, nd.ni_vp); return (0); } static int unprivileged_chroot = 0; SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_chroot, CTLFLAG_RW, &unprivileged_chroot, 0, "Unprivileged processes can use chroot(2)"); /* * Takes locked vnode, unlocks it before returning. */ static int kern_chroot(struct thread *td, struct vnode *vp) { struct proc *p; int error; error = priv_check(td, PRIV_VFS_CHROOT); if (error != 0) { p = td->td_proc; if (unprivileged_chroot == 0) { error = EXTERROR(EPERM, "security.bsd.unprivileged_chroot sysctl not enabled"); goto e_vunlock; } if ((p->p_flag2 & P2_NO_NEW_PRIVS) == 0) { error = EXTERROR(EPERM, "PROC_NO_NEW_PRIVS not enabled"); goto e_vunlock; } } error = change_dir(vp, td); if (error != 0) goto e_vunlock; #ifdef MAC error = mac_vnode_check_chroot(td->td_ucred, vp); if (error != 0) goto e_vunlock; #endif VOP_UNLOCK(vp); error = pwd_chroot(td, vp); vrele(vp); return (error); e_vunlock: vput(vp); return (error); } /* * Change notion of root (``/'') directory. */ #ifndef _SYS_SYSPROTO_H_ struct chroot_args { char *path; }; #endif int sys_chroot(struct thread *td, struct chroot_args *uap) { struct nameidata nd; int error; NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, uap->path); error = namei(&nd); if (error != 0) return (error); NDFREE_PNBUF(&nd); error = kern_chroot(td, nd.ni_vp); return (error); } /* * Change notion of root directory to a given file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct fchroot_args { int fd; }; #endif int sys_fchroot(struct thread *td, struct fchroot_args *uap) { struct vnode *vp; struct file *fp; int error; uint8_t fdflags; error = getvnode_path(td, uap->fd, &cap_fchroot_rights, &fdflags, &fp); if (error != 0) return (error); if ((fdflags & UF_RESOLVE_BENEATH) != 0) { fdrop(fp, td); return (ENOTCAPABLE); } vp = fp->f_vnode; vrefact(vp); fdrop(fp, td); vn_lock(vp, LK_SHARED | LK_RETRY); error = kern_chroot(td, vp); return (error); } /* * Common routine for chroot and chdir. Callers must provide a locked vnode * instance. */ int change_dir(struct vnode *vp, struct thread *td) { #ifdef MAC int error; #endif ASSERT_VOP_LOCKED(vp, "change_dir(): vp not locked"); if (vp->v_type != VDIR) return (ENOTDIR); #ifdef MAC error = mac_vnode_check_chdir(td->td_ucred, vp); if (error != 0) return (error); #endif return (VOP_ACCESS(vp, VEXEC, td->td_ucred, td)); } static __inline void flags_to_rights(int flags, cap_rights_t *rightsp) { if (flags & O_EXEC) { cap_rights_set_one(rightsp, CAP_FEXECVE); if (flags & O_PATH) return; } else { switch ((flags & O_ACCMODE)) { case O_RDONLY: cap_rights_set_one(rightsp, CAP_READ); break; case O_RDWR: cap_rights_set_one(rightsp, CAP_READ); /* FALLTHROUGH */ case O_WRONLY: cap_rights_set_one(rightsp, CAP_WRITE); if (!(flags & (O_APPEND | O_TRUNC))) cap_rights_set_one(rightsp, CAP_SEEK); break; } } if (flags & O_CREAT) cap_rights_set_one(rightsp, CAP_CREATE); if (flags & O_TRUNC) cap_rights_set_one(rightsp, CAP_FTRUNCATE); if (flags & (O_SYNC | O_FSYNC)) cap_rights_set_one(rightsp, CAP_FSYNC); if (flags & (O_EXLOCK | O_SHLOCK)) cap_rights_set_one(rightsp, CAP_FLOCK); } /* * Check permissions, allocate an open file structure, and call the device * open routine if any. */ #ifndef _SYS_SYSPROTO_H_ struct open_args { char *path; int flags; int mode; }; #endif int sys_open(struct thread *td, struct open_args *uap) { return (kern_openat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->flags, uap->mode)); } #ifndef _SYS_SYSPROTO_H_ struct openat_args { int fd; char *path; int flag; int mode; }; #endif int sys_openat(struct thread *td, struct openat_args *uap) { AUDIT_ARG_FD(uap->fd); return (kern_openat(td, uap->fd, uap->path, UIO_USERSPACE, uap->flag, uap->mode)); } /* * Validate open(2) flags and convert access mode flags (O_RDONLY etc.) to their * in-kernel representations (FREAD etc.). */ static int openflags(int *flagsp) { int flags; /* * Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags * may be specified. On the other hand, for O_PATH any mode * except O_EXEC is ignored. */ flags = *flagsp; if ((flags & O_PATH) != 0) { flags &= ~O_ACCMODE; } else if ((flags & O_EXEC) != 0) { if ((flags & O_ACCMODE) != 0) return (EINVAL); } else if ((flags & O_ACCMODE) == O_ACCMODE) { return (EINVAL); } else { flags = FFLAGS(flags); } *flagsp = flags; return (0); } static void finit_open(struct file *fp, struct vnode *vp, int flags) { /* * Store the vnode, for any f_type. Typically, the vnode use count is * decremented by a direct call to vnops.fo_close() for files that * switched type. */ fp->f_vnode = vp; /* * If the file wasn't claimed by devfs or fifofs, bind it to the normal * vnode operations here. */ if (fp->f_ops == &badfileops) { KASSERT(vp->v_type != VFIFO || (flags & O_PATH) != 0, ("Unexpected fifo fp %p vp %p", fp, vp)); if ((flags & O_PATH) != 0) { finit(fp, (flags & FMASK) | (fp->f_flag & FKQALLOWED), DTYPE_VNODE, NULL, &path_fileops); } else { finit_vnode(fp, flags, NULL, &vnops); } } } /* * If fpp != NULL, opened file is not installed into the file * descriptor table, instead it is returned in *fpp. This is * incompatible with fdopen(), in which case we return EINVAL. */ static int openatfp(struct thread *td, int dirfd, const char *path, enum uio_seg pathseg, int flags, int mode, struct file **fpp) { struct proc *p; struct filedesc *fdp; struct pwddesc *pdp; struct file *fp; struct vnode *vp; struct filecaps *fcaps; struct nameidata nd; cap_rights_t rights; int cmode, error, indx; indx = -1; p = td->td_proc; fdp = p->p_fd; pdp = p->p_pd; AUDIT_ARG_FFLAGS(flags); AUDIT_ARG_MODE(mode); cap_rights_init_one(&rights, CAP_LOOKUP); flags_to_rights(flags, &rights); error = openflags(&flags); if (error != 0) return (error); /* * Allocate a file structure. The descriptor to reference it * is allocated and used by finstall_refed() below. */ error = falloc_noinstall(td, &fp); if (error != 0) return (error); /* Set the flags early so the finit in devfs can pick them up. */ fp->f_flag = flags & FMASK; cmode = ((mode & ~pdp->pd_cmask) & ALLPERMS) & ~S_ISTXT; NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | WANTIOCTLCAPS, pathseg, path, dirfd, &rights); td->td_dupfd = -1; /* XXX check for fdopen */ error = vn_open_cred(&nd, &flags, cmode, VN_OPEN_WANTIOCTLCAPS, td->td_ucred, fp); if (error != 0) { /* * If the vn_open replaced the method vector, something * wonderous happened deep below and we just pass it up * pretending we know what we do. */ if (error == ENXIO && fp->f_ops != &badfileops) { MPASS((flags & O_PATH) == 0); goto success; } /* * Handle special fdopen() case. bleh. * * Don't do this for relative (capability) lookups; we don't * understand exactly what would happen, and we don't think * that it ever should. */ if ((nd.ni_resflags & NIRES_STRICTREL) == 0 && (error == ENODEV || error == ENXIO) && td->td_dupfd >= 0) { MPASS(fpp == NULL); error = dupfdopen(td, fdp, td->td_dupfd, flags, error, &indx); if (error == 0) goto success; } goto bad; } td->td_dupfd = 0; NDFREE_PNBUF(&nd); vp = nd.ni_vp; finit_open(fp, vp, flags); VOP_UNLOCK(vp); if (flags & O_TRUNC) { error = fo_truncate(fp, 0, td->td_ucred, td); if (error != 0) goto bad; } success: if (fpp != NULL) { MPASS(error == 0); NDFREE_IOCTLCAPS(&nd); *fpp = fp; return (0); } /* * If we haven't already installed the FD (for dupfdopen), do so now. */ if (indx == -1) { #ifdef CAPABILITIES if ((nd.ni_resflags & NIRES_STRICTREL) != 0) fcaps = &nd.ni_filecaps; else #endif fcaps = NULL; if ((nd.ni_resflags & NIRES_BENEATH) != 0) flags |= O_RESOLVE_BENEATH; else flags &= ~O_RESOLVE_BENEATH; error = finstall_refed(td, fp, &indx, flags, fcaps); /* On success finstall_refed() consumes fcaps. */ if (error != 0) { goto bad; } } else { NDFREE_IOCTLCAPS(&nd); falloc_abort(td, fp); } td->td_retval[0] = indx; return (0); bad: KASSERT(indx == -1, ("indx=%d, should be -1", indx)); NDFREE_IOCTLCAPS(&nd); falloc_abort(td, fp); return (error); } int kern_openat(struct thread *td, int dirfd, const char *path, enum uio_seg pathseg, int flags, int mode) { return (openatfp(td, dirfd, path, pathseg, flags, mode, NULL)); } int kern_openatfp(struct thread *td, int dirfd, const char *path, enum uio_seg pathseg, int flags, int mode, struct file **fpp) { int error, old_dupfd; old_dupfd = td->td_dupfd; td->td_dupfd = -1; error = openatfp(td, dirfd, path, pathseg, flags, mode, fpp); td->td_dupfd = old_dupfd; return (error); } #ifdef COMPAT_43 /* * Create a file. */ #ifndef _SYS_SYSPROTO_H_ struct ocreat_args { char *path; int mode; }; #endif int ocreat(struct thread *td, struct ocreat_args *uap) { return (kern_openat(td, AT_FDCWD, uap->path, UIO_USERSPACE, O_WRONLY | O_CREAT | O_TRUNC, uap->mode)); } #endif /* COMPAT_43 */ /* * Create a special file. */ #ifndef _SYS_SYSPROTO_H_ struct mknodat_args { int fd; char *path; mode_t mode; dev_t dev; }; #endif int sys_mknodat(struct thread *td, struct mknodat_args *uap) { return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode, uap->dev)); } #if defined(COMPAT_FREEBSD11) int freebsd11_mknod(struct thread *td, struct freebsd11_mknod_args *uap) { return (kern_mknodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->mode, uap->dev)); } int freebsd11_mknodat(struct thread *td, struct freebsd11_mknodat_args *uap) { return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode, uap->dev)); } #endif /* COMPAT_FREEBSD11 */ int kern_mknodat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, int mode, dev_t dev) { struct vnode *vp; struct mount *mp; struct vattr vattr; struct nameidata nd; int error, whiteout = 0; AUDIT_ARG_MODE(mode); AUDIT_ARG_DEV(dev); switch (mode & S_IFMT) { case S_IFCHR: case S_IFBLK: error = priv_check(td, PRIV_VFS_MKNOD_DEV); if (error == 0 && dev == VNOVAL) error = EINVAL; break; case S_IFWHT: error = priv_check(td, PRIV_VFS_MKNOD_WHT); break; case S_IFIFO: if (dev == 0) return (kern_mkfifoat(td, fd, path, pathseg, mode)); /* FALLTHROUGH */ default: error = EINVAL; break; } if (error != 0) return (error); NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | AUDITVNODE1 | NOCACHE, pathseg, path, fd, &cap_mknodat_rights); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; if (vp != NULL) { NDFREE_PNBUF(&nd); if (vp == nd.ni_dvp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); vrele(vp); return (EEXIST); } else if ((vn_irflag_read(nd.ni_dvp) & VIRF_NAMEDDIR) != 0) { NDFREE_PNBUF(&nd); vput(nd.ni_dvp); return (EINVAL); } else { VATTR_NULL(&vattr); vattr.va_mode = (mode & ALLPERMS) & ~td->td_proc->p_pd->pd_cmask; vattr.va_rdev = dev; whiteout = 0; switch (mode & S_IFMT) { case S_IFCHR: vattr.va_type = VCHR; break; case S_IFBLK: vattr.va_type = VBLK; break; case S_IFWHT: whiteout = 1; break; default: panic("kern_mknod: invalid mode"); } } if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { NDFREE_PNBUF(&nd); vput(nd.ni_dvp); if ((error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH)) != 0) return (error); goto restart; } #ifdef MAC if (error == 0 && !whiteout) error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); #endif if (error == 0) { if (whiteout) error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); else { error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); } } VOP_VPUT_PAIR(nd.ni_dvp, error == 0 && !whiteout ? &nd.ni_vp : NULL, true); vn_finished_write(mp); NDFREE_PNBUF(&nd); if (error == ERELOOKUP) goto restart; return (error); } /* * Create a named pipe. */ #ifndef _SYS_SYSPROTO_H_ struct mkfifo_args { char *path; int mode; }; #endif int sys_mkfifo(struct thread *td, struct mkfifo_args *uap) { return (kern_mkfifoat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->mode)); } #ifndef _SYS_SYSPROTO_H_ struct mkfifoat_args { int fd; char *path; mode_t mode; }; #endif int sys_mkfifoat(struct thread *td, struct mkfifoat_args *uap) { return (kern_mkfifoat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode)); } int kern_mkfifoat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, int mode) { struct mount *mp; struct vattr vattr; struct nameidata nd; int error; AUDIT_ARG_MODE(mode); NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | AUDITVNODE1 | NOCACHE, pathseg, path, fd, &cap_mkfifoat_rights); if ((error = namei(&nd)) != 0) return (error); if (nd.ni_vp != NULL) { NDFREE_PNBUF(&nd); if (nd.ni_vp == nd.ni_dvp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); vrele(nd.ni_vp); return (EEXIST); } if ((vn_irflag_read(nd.ni_dvp) & VIRF_NAMEDDIR) != 0) { NDFREE_PNBUF(&nd); vput(nd.ni_dvp); return (EINVAL); } if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { NDFREE_PNBUF(&nd); vput(nd.ni_dvp); if ((error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH)) != 0) return (error); goto restart; } VATTR_NULL(&vattr); vattr.va_type = VFIFO; vattr.va_mode = (mode & ALLPERMS) & ~td->td_proc->p_pd->pd_cmask; #ifdef MAC error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); if (error != 0) goto out; #endif error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); #ifdef MAC out: #endif VOP_VPUT_PAIR(nd.ni_dvp, error == 0 ? &nd.ni_vp : NULL, true); vn_finished_write(mp); NDFREE_PNBUF(&nd); if (error == ERELOOKUP) goto restart; return (error); } /* * Make a hard file link. */ #ifndef _SYS_SYSPROTO_H_ struct link_args { char *path; char *link; }; #endif int sys_link(struct thread *td, struct link_args *uap) { return (kern_linkat(td, AT_FDCWD, AT_FDCWD, uap->path, uap->link, UIO_USERSPACE, AT_SYMLINK_FOLLOW)); } #ifndef _SYS_SYSPROTO_H_ struct linkat_args { int fd1; char *path1; int fd2; char *path2; int flag; }; #endif int sys_linkat(struct thread *td, struct linkat_args *uap) { return (kern_linkat(td, uap->fd1, uap->fd2, uap->path1, uap->path2, UIO_USERSPACE, uap->flag)); } int hardlink_check_uid = 0; SYSCTL_INT(_security_bsd, OID_AUTO, hardlink_check_uid, CTLFLAG_RW, &hardlink_check_uid, 0, "Unprivileged processes cannot create hard links to files owned by other " "users"); static int hardlink_check_gid = 0; SYSCTL_INT(_security_bsd, OID_AUTO, hardlink_check_gid, CTLFLAG_RW, &hardlink_check_gid, 0, "Unprivileged processes cannot create hard links to files owned by other " "groups"); static int can_hardlink(struct vnode *vp, struct ucred *cred) { struct vattr va; int error; if (!hardlink_check_uid && !hardlink_check_gid) return (0); error = VOP_GETATTR(vp, &va, cred); if (error != 0) return (error); if (hardlink_check_uid && cred->cr_uid != va.va_uid) { error = priv_check_cred(cred, PRIV_VFS_LINK); if (error != 0) return (error); } if (hardlink_check_gid && !groupmember(va.va_gid, cred)) { error = priv_check_cred(cred, PRIV_VFS_LINK); if (error != 0) return (error); } return (0); } int kern_linkat(struct thread *td, int fd1, int fd2, const char *path1, const char *path2, enum uio_seg segflag, int flag) { struct nameidata nd; int error; if ((flag & ~(AT_SYMLINK_FOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH)) != 0) return (EINVAL); NDPREINIT(&nd); do { bwillwrite(); NDINIT_ATRIGHTS(&nd, LOOKUP, AUDITVNODE1 | at2cnpflags(flag, AT_SYMLINK_FOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH), segflag, path1, fd1, &cap_linkat_source_rights); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); if ((nd.ni_resflags & NIRES_EMPTYPATH) != 0) { error = priv_check(td, PRIV_VFS_FHOPEN); if (error != 0) { vrele(nd.ni_vp); return (error); } } error = kern_linkat_vp(td, nd.ni_vp, fd2, path2, segflag); } while (error == EAGAIN || error == ERELOOKUP); return (error); } static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path, enum uio_seg segflag) { struct nameidata nd; struct mount *mp; int error; if (vp->v_type == VDIR) { vrele(vp); return (EPERM); /* POSIX */ } if ((vn_irflag_read(vp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0) { vrele(vp); return (EINVAL); } NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | AUDITVNODE2 | NOCACHE, segflag, path, fd, &cap_linkat_target_rights); if ((error = namei(&nd)) == 0) { if (nd.ni_vp != NULL) { NDFREE_PNBUF(&nd); if (nd.ni_dvp == nd.ni_vp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); vrele(nd.ni_vp); vrele(vp); return (EEXIST); } else if (nd.ni_dvp->v_mount != vp->v_mount) { /* * Cross-device link. No need to recheck * vp->v_type, since it cannot change, except * to VBAD. */ NDFREE_PNBUF(&nd); vput(nd.ni_dvp); vrele(vp); return (EXDEV); } else if (vn_lock(vp, LK_EXCLUSIVE) == 0) { error = can_hardlink(vp, td->td_ucred); #ifdef MAC if (error == 0) error = mac_vnode_check_link(td->td_ucred, nd.ni_dvp, vp, &nd.ni_cnd); #endif if (error != 0) { vput(vp); vput(nd.ni_dvp); NDFREE_PNBUF(&nd); return (error); } error = vn_start_write(vp, &mp, V_NOWAIT); if (error != 0) { vput(vp); vput(nd.ni_dvp); NDFREE_PNBUF(&nd); error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH); if (error != 0) return (error); return (EAGAIN); } error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); VOP_VPUT_PAIR(nd.ni_dvp, &vp, true); vn_finished_write(mp); NDFREE_PNBUF(&nd); vp = NULL; } else { vput(nd.ni_dvp); NDFREE_PNBUF(&nd); vrele(vp); return (EAGAIN); } } if (vp != NULL) vrele(vp); return (error); } /* * Make a symbolic link. */ #ifndef _SYS_SYSPROTO_H_ struct symlink_args { char *path; char *link; }; #endif int sys_symlink(struct thread *td, struct symlink_args *uap) { return (kern_symlinkat(td, uap->path, AT_FDCWD, uap->link, UIO_USERSPACE)); } #ifndef _SYS_SYSPROTO_H_ struct symlinkat_args { char *path; int fd; char *path2; }; #endif int sys_symlinkat(struct thread *td, struct symlinkat_args *uap) { return (kern_symlinkat(td, uap->path1, uap->fd, uap->path2, UIO_USERSPACE)); } int kern_symlinkat(struct thread *td, const char *path1, int fd, const char *path2, enum uio_seg segflg) { struct mount *mp; struct vattr vattr; const char *syspath; char *tmppath; struct nameidata nd; int error; if (segflg == UIO_SYSSPACE) { syspath = path1; } else { tmppath = uma_zalloc(namei_zone, M_WAITOK); if ((error = copyinstr(path1, tmppath, MAXPATHLEN, NULL)) != 0) goto out; syspath = tmppath; } AUDIT_ARG_TEXT(syspath); NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | AUDITVNODE1 | NOCACHE, segflg, path2, fd, &cap_symlinkat_rights); if ((error = namei(&nd)) != 0) goto out; if (nd.ni_vp) { NDFREE_PNBUF(&nd); if (nd.ni_vp == nd.ni_dvp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); vrele(nd.ni_vp); nd.ni_vp = NULL; error = EEXIST; goto out; } if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { NDFREE_PNBUF(&nd); vput(nd.ni_dvp); if ((error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH)) != 0) goto out; goto restart; } if ((vn_irflag_read(nd.ni_dvp) & VIRF_NAMEDDIR) != 0) { error = EINVAL; goto out; } VATTR_NULL(&vattr); vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_pd->pd_cmask; #ifdef MAC vattr.va_type = VLNK; error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); if (error != 0) goto out2; #endif error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, syspath); #ifdef MAC out2: #endif VOP_VPUT_PAIR(nd.ni_dvp, error == 0 ? &nd.ni_vp : NULL, true); vn_finished_write(mp); NDFREE_PNBUF(&nd); if (error == ERELOOKUP) goto restart; out: if (segflg != UIO_SYSSPACE) uma_zfree(namei_zone, tmppath); return (error); } /* * Delete a whiteout from the filesystem. */ #ifndef _SYS_SYSPROTO_H_ struct undelete_args { char *path; }; #endif int sys_undelete(struct thread *td, struct undelete_args *uap) { struct mount *mp; struct nameidata nd; int error; NDPREINIT(&nd); restart: bwillwrite(); NDINIT(&nd, DELETE, LOCKPARENT | DOWHITEOUT | AUDITVNODE1, UIO_USERSPACE, uap->path); error = namei(&nd); if (error != 0) return (error); if (nd.ni_vp != NULL || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { NDFREE_PNBUF(&nd); if (nd.ni_vp == nd.ni_dvp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); if (nd.ni_vp) vrele(nd.ni_vp); return (EEXIST); } if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { NDFREE_PNBUF(&nd); vput(nd.ni_dvp); if ((error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH)) != 0) return (error); goto restart; } error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE); NDFREE_PNBUF(&nd); vput(nd.ni_dvp); vn_finished_write(mp); if (error == ERELOOKUP) goto restart; return (error); } /* * Delete a name from the filesystem. */ #ifndef _SYS_SYSPROTO_H_ struct unlink_args { char *path; }; #endif int sys_unlink(struct thread *td, struct unlink_args *uap) { return (kern_funlinkat(td, AT_FDCWD, uap->path, FD_NONE, UIO_USERSPACE, 0, 0)); } static int kern_funlinkat_ex(struct thread *td, int dfd, const char *path, int fd, int flag, enum uio_seg pathseg, ino_t oldinum) { if ((flag & ~(AT_REMOVEDIR | AT_RESOLVE_BENEATH)) != 0) return (EINVAL); if ((flag & AT_REMOVEDIR) != 0) return (kern_frmdirat(td, dfd, path, fd, UIO_USERSPACE, 0)); return (kern_funlinkat(td, dfd, path, fd, UIO_USERSPACE, 0, 0)); } #ifndef _SYS_SYSPROTO_H_ struct unlinkat_args { int fd; char *path; int flag; }; #endif int sys_unlinkat(struct thread *td, struct unlinkat_args *uap) { return (kern_funlinkat_ex(td, uap->fd, uap->path, FD_NONE, uap->flag, UIO_USERSPACE, 0)); } #ifndef _SYS_SYSPROTO_H_ struct funlinkat_args { int dfd; const char *path; int fd; int flag; }; #endif int sys_funlinkat(struct thread *td, struct funlinkat_args *uap) { return (kern_funlinkat_ex(td, uap->dfd, uap->path, uap->fd, uap->flag, UIO_USERSPACE, 0)); } int kern_funlinkat(struct thread *td, int dfd, const char *path, int fd, enum uio_seg pathseg, int flag, ino_t oldinum) { struct mount *mp; struct file *fp; struct vnode *vp; struct nameidata nd; struct stat sb; int error; fp = NULL; if (fd != FD_NONE) { error = getvnode_path(td, fd, &cap_no_rights, NULL, &fp); if (error != 0) return (error); } NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | at2cnpflags(flag, AT_RESOLVE_BENEATH), pathseg, path, dfd, &cap_unlinkat_rights); if ((error = namei(&nd)) != 0) { if (error == EINVAL) error = EPERM; goto fdout; } vp = nd.ni_vp; if (vp->v_type == VDIR && oldinum == 0) { error = EPERM; /* POSIX */ } else if (oldinum != 0 && ((error = VOP_STAT(vp, &sb, td->td_ucred, NOCRED)) == 0) && sb.st_ino != oldinum) { error = EIDRM; /* Identifier removed */ } else if (fp != NULL && fp->f_vnode != vp) { if (VN_IS_DOOMED(fp->f_vnode)) error = EBADF; else error = EDEADLK; } else { /* * The root of a mounted filesystem cannot be deleted. * * XXX: can this only be a VDIR case? */ if (vp->v_vflag & VV_ROOT) error = EBUSY; } if (error == 0) { if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { NDFREE_PNBUF(&nd); vput(nd.ni_dvp); if (vp == nd.ni_dvp) vrele(vp); else vput(vp); if ((error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH)) != 0) { goto fdout; } goto restart; } #ifdef MAC error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp, &nd.ni_cnd); if (error != 0) goto out; #endif error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); #ifdef MAC out: #endif vn_finished_write(mp); } NDFREE_PNBUF(&nd); vput(nd.ni_dvp); if (vp == nd.ni_dvp) vrele(vp); else vput(vp); if (error == ERELOOKUP) goto restart; fdout: if (fp != NULL) fdrop(fp, td); return (error); } /* * Reposition read/write file offset. */ #ifndef _SYS_SYSPROTO_H_ struct lseek_args { int fd; int pad; off_t offset; int whence; }; #endif int sys_lseek(struct thread *td, struct lseek_args *uap) { return (kern_lseek(td, uap->fd, uap->offset, uap->whence)); } int kern_lseek(struct thread *td, int fd, off_t offset, int whence) { struct file *fp; int error; AUDIT_ARG_FD(fd); error = fget(td, fd, &cap_seek_rights, &fp); if (error != 0) return (error); error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ? fo_seek(fp, offset, whence, td) : ESPIPE; fdrop(fp, td); return (error); } #if defined(COMPAT_43) /* * Reposition read/write file offset. */ #ifndef _SYS_SYSPROTO_H_ struct olseek_args { int fd; long offset; int whence; }; #endif int olseek(struct thread *td, struct olseek_args *uap) { return (kern_lseek(td, uap->fd, uap->offset, uap->whence)); } #endif /* COMPAT_43 */ #if defined(COMPAT_FREEBSD6) /* Version with the 'pad' argument */ int freebsd6_lseek(struct thread *td, struct freebsd6_lseek_args *uap) { return (kern_lseek(td, uap->fd, uap->offset, uap->whence)); } #endif /* * Check access permissions using passed credentials. */ static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred, struct thread *td) { accmode_t accmode; int error; /* Flags == 0 means only check for existence. */ if (user_flags == 0) return (0); accmode = 0; if (user_flags & R_OK) accmode |= VREAD; if (user_flags & W_OK) accmode |= VWRITE; if (user_flags & X_OK) accmode |= VEXEC; #ifdef MAC error = mac_vnode_check_access(cred, vp, accmode); if (error != 0) return (error); #endif if ((accmode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) error = VOP_ACCESS(vp, accmode, cred, td); return (error); } /* * Check access permissions using "real" credentials. */ #ifndef _SYS_SYSPROTO_H_ struct access_args { char *path; int amode; }; #endif int sys_access(struct thread *td, struct access_args *uap) { return (kern_accessat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0, uap->amode)); } #ifndef _SYS_SYSPROTO_H_ struct faccessat_args { int dirfd; char *path; int amode; int flag; } #endif int sys_faccessat(struct thread *td, struct faccessat_args *uap) { return (kern_accessat(td, uap->fd, uap->path, UIO_USERSPACE, uap->flag, uap->amode)); } int kern_accessat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, int flag, int amode) { struct ucred *cred, *usecred; struct vnode *vp; struct nameidata nd; int error; if ((flag & ~(AT_EACCESS | AT_RESOLVE_BENEATH | AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) != 0) return (EINVAL); if (amode != F_OK && (amode & ~(R_OK | W_OK | X_OK)) != 0) return (EINVAL); /* * Create and modify a temporary credential instead of one that * is potentially shared (if we need one). */ cred = td->td_ucred; if ((flag & AT_EACCESS) == 0 && ((cred->cr_uid != cred->cr_ruid || cred->cr_rgid != cred->cr_gid))) { usecred = crdup(cred); usecred->cr_uid = cred->cr_ruid; usecred->cr_gid = cred->cr_rgid; td->td_ucred = usecred; } else usecred = cred; AUDIT_ARG_VALUE(amode); NDINIT_ATRIGHTS(&nd, LOOKUP, LOCKSHARED | LOCKLEAF | AUDITVNODE1 | at2cnpflags(flag, AT_RESOLVE_BENEATH | AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH), pathseg, path, fd, &cap_fstat_rights); if ((error = namei(&nd)) != 0) goto out; vp = nd.ni_vp; error = vn_access(vp, amode, usecred, td); NDFREE_PNBUF(&nd); vput(vp); out: if (usecred != cred) { td->td_ucred = cred; crfree(usecred); } return (error); } /* * Check access permissions using "effective" credentials. */ #ifndef _SYS_SYSPROTO_H_ struct eaccess_args { char *path; int amode; }; #endif int sys_eaccess(struct thread *td, struct eaccess_args *uap) { return (kern_accessat(td, AT_FDCWD, uap->path, UIO_USERSPACE, AT_EACCESS, uap->amode)); } #if defined(COMPAT_43) /* * Get file status; this version follows links. */ #ifndef _SYS_SYSPROTO_H_ struct ostat_args { char *path; struct ostat *ub; }; #endif int ostat(struct thread *td, struct ostat_args *uap) { struct stat sb; struct ostat osb; int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); cvtstat(&sb, &osb); return (copyout(&osb, uap->ub, sizeof (osb))); } /* * Get file status; this version does not follow links. */ #ifndef _SYS_SYSPROTO_H_ struct olstat_args { char *path; struct ostat *ub; }; #endif int olstat(struct thread *td, struct olstat_args *uap) { struct stat sb; struct ostat osb; int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); cvtstat(&sb, &osb); return (copyout(&osb, uap->ub, sizeof (osb))); } /* * Convert from an old to a new stat structure. * XXX: many values are blindly truncated. */ void cvtstat(struct stat *st, struct ostat *ost) { bzero(ost, sizeof(*ost)); ost->st_dev = st->st_dev; ost->st_ino = st->st_ino; ost->st_mode = st->st_mode; ost->st_nlink = st->st_nlink; ost->st_uid = st->st_uid; ost->st_gid = st->st_gid; ost->st_rdev = st->st_rdev; ost->st_size = MIN(st->st_size, INT32_MAX); ost->st_atim = st->st_atim; ost->st_mtim = st->st_mtim; ost->st_ctim = st->st_ctim; ost->st_blksize = st->st_blksize; ost->st_blocks = st->st_blocks; ost->st_flags = st->st_flags; ost->st_gen = st->st_gen; } #endif /* COMPAT_43 */ #if defined(COMPAT_43) || defined(COMPAT_FREEBSD11) int ino64_trunc_error; SYSCTL_INT(_vfs, OID_AUTO, ino64_trunc_error, CTLFLAG_RW, &ino64_trunc_error, 0, "Error on truncation of device, file or inode number, or link count"); int freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost) { ost->st_dev = st->st_dev; if (ost->st_dev != st->st_dev) { switch (ino64_trunc_error) { default: /* * Since dev_t is almost raw, don't clamp to the * maximum for case 2, but ignore the error. */ break; case 1: return (EOVERFLOW); } } ost->st_ino = st->st_ino; if (ost->st_ino != st->st_ino) { switch (ino64_trunc_error) { default: case 0: break; case 1: return (EOVERFLOW); case 2: ost->st_ino = UINT32_MAX; break; } } ost->st_mode = st->st_mode; ost->st_nlink = st->st_nlink; if (ost->st_nlink != st->st_nlink) { switch (ino64_trunc_error) { default: case 0: break; case 1: return (EOVERFLOW); case 2: ost->st_nlink = UINT16_MAX; break; } } ost->st_uid = st->st_uid; ost->st_gid = st->st_gid; ost->st_rdev = st->st_rdev; if (ost->st_rdev != st->st_rdev) { switch (ino64_trunc_error) { default: break; case 1: return (EOVERFLOW); } } ost->st_atim = st->st_atim; ost->st_mtim = st->st_mtim; ost->st_ctim = st->st_ctim; ost->st_size = st->st_size; ost->st_blocks = st->st_blocks; ost->st_blksize = st->st_blksize; ost->st_flags = st->st_flags; ost->st_gen = st->st_gen; ost->st_lspare = 0; ost->st_birthtim = st->st_birthtim; bzero((char *)&ost->st_birthtim + sizeof(ost->st_birthtim), sizeof(*ost) - offsetof(struct freebsd11_stat, st_birthtim) - sizeof(ost->st_birthtim)); return (0); } int freebsd11_stat(struct thread *td, struct freebsd11_stat_args* uap) { struct stat sb; struct freebsd11_stat osb; int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); if (error == 0) error = copyout(&osb, uap->ub, sizeof(osb)); return (error); } int freebsd11_lstat(struct thread *td, struct freebsd11_lstat_args* uap) { struct stat sb; struct freebsd11_stat osb; int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); if (error == 0) error = copyout(&osb, uap->ub, sizeof(osb)); return (error); } int freebsd11_fhstat(struct thread *td, struct freebsd11_fhstat_args* uap) { struct fhandle fh; struct stat sb; struct freebsd11_stat osb; int error; error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); if (error != 0) return (error); error = kern_fhstat(td, fh, &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); if (error == 0) error = copyout(&osb, uap->sb, sizeof(osb)); return (error); } int freebsd11_fstatat(struct thread *td, struct freebsd11_fstatat_args* uap) { struct stat sb; struct freebsd11_stat osb; int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); if (error == 0) error = copyout(&osb, uap->buf, sizeof(osb)); return (error); } #endif /* COMPAT_FREEBSD11 */ /* * Get file status */ #ifndef _SYS_SYSPROTO_H_ struct fstatat_args { int fd; char *path; struct stat *buf; int flag; } #endif int sys_fstatat(struct thread *td, struct fstatat_args *uap) { struct stat sb; int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE, &sb); if (error == 0) error = copyout(&sb, uap->buf, sizeof (sb)); return (error); } int kern_statat(struct thread *td, int flag, int fd, const char *path, enum uio_seg pathseg, struct stat *sbp) { struct nameidata nd; int error; if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH)) != 0) return (EINVAL); NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH | AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights); if ((error = namei(&nd)) != 0) { if (error == ENOTDIR && (nd.ni_resflags & NIRES_EMPTYPATH) != 0) error = kern_fstat(td, fd, sbp); return (error); } error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED); NDFREE_PNBUF(&nd); vput(nd.ni_vp); #ifdef __STAT_TIME_T_EXT sbp->st_atim_ext = 0; sbp->st_mtim_ext = 0; sbp->st_ctim_ext = 0; sbp->st_btim_ext = 0; #endif #ifdef KTRACE if (KTRPOINT(td, KTR_STRUCT)) ktrstat_error(sbp, error); #endif return (error); } #if defined(COMPAT_FREEBSD11) /* * Implementation of the NetBSD [l]stat() functions. */ int freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb) { struct freebsd11_stat sb11; int error; error = freebsd11_cvtstat(sb, &sb11); if (error != 0) return (error); bzero(nsb, sizeof(*nsb)); CP(sb11, *nsb, st_dev); CP(sb11, *nsb, st_ino); CP(sb11, *nsb, st_mode); CP(sb11, *nsb, st_nlink); CP(sb11, *nsb, st_uid); CP(sb11, *nsb, st_gid); CP(sb11, *nsb, st_rdev); CP(sb11, *nsb, st_atim); CP(sb11, *nsb, st_mtim); CP(sb11, *nsb, st_ctim); CP(sb11, *nsb, st_size); CP(sb11, *nsb, st_blocks); CP(sb11, *nsb, st_blksize); CP(sb11, *nsb, st_flags); CP(sb11, *nsb, st_gen); CP(sb11, *nsb, st_birthtim); return (0); } #ifndef _SYS_SYSPROTO_H_ struct freebsd11_nstat_args { char *path; struct nstat *ub; }; #endif int freebsd11_nstat(struct thread *td, struct freebsd11_nstat_args *uap) { struct stat sb; struct nstat nsb; int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtnstat(&sb, &nsb); if (error == 0) error = copyout(&nsb, uap->ub, sizeof (nsb)); return (error); } /* * NetBSD lstat. Get file status; this version does not follow links. */ #ifndef _SYS_SYSPROTO_H_ struct freebsd11_nlstat_args { char *path; struct nstat *ub; }; #endif int freebsd11_nlstat(struct thread *td, struct freebsd11_nlstat_args *uap) { struct stat sb; struct nstat nsb; int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtnstat(&sb, &nsb); if (error == 0) error = copyout(&nsb, uap->ub, sizeof (nsb)); return (error); } #endif /* COMPAT_FREEBSD11 */ /* * Get configurable pathname variables. */ #ifndef _SYS_SYSPROTO_H_ struct pathconf_args { char *path; int name; }; #endif int sys_pathconf(struct thread *td, struct pathconf_args *uap) { long value; int error; error = kern_pathconf(td, uap->path, UIO_USERSPACE, uap->name, FOLLOW, &value); if (error == 0) td->td_retval[0] = value; return (error); } #ifndef _SYS_SYSPROTO_H_ struct lpathconf_args { char *path; int name; }; #endif int sys_lpathconf(struct thread *td, struct lpathconf_args *uap) { long value; int error; error = kern_pathconf(td, uap->path, UIO_USERSPACE, uap->name, NOFOLLOW, &value); if (error == 0) td->td_retval[0] = value; return (error); } int kern_pathconf(struct thread *td, const char *path, enum uio_seg pathseg, int name, u_long flags, long *valuep) { struct nameidata nd; int error; NDINIT(&nd, LOOKUP, LOCKSHARED | LOCKLEAF | AUDITVNODE1 | flags, pathseg, path); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); error = VOP_PATHCONF(nd.ni_vp, name, valuep); vput(nd.ni_vp); return (error); } /* * Return target name of a symbolic link. */ #ifndef _SYS_SYSPROTO_H_ struct readlink_args { char *path; char *buf; size_t count; }; #endif int sys_readlink(struct thread *td, struct readlink_args *uap) { return (kern_readlinkat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->buf, UIO_USERSPACE, uap->count)); } #ifndef _SYS_SYSPROTO_H_ struct readlinkat_args { int fd; char *path; char *buf; size_t bufsize; }; #endif int sys_readlinkat(struct thread *td, struct readlinkat_args *uap) { return (kern_readlinkat(td, uap->fd, uap->path, UIO_USERSPACE, uap->buf, UIO_USERSPACE, uap->bufsize)); } int kern_readlinkat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, char *buf, enum uio_seg bufseg, size_t count) { struct vnode *vp; struct nameidata nd; int error; if (count > IOSIZE_MAX) return (EINVAL); NDINIT_AT(&nd, LOOKUP, NOFOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1 | EMPTYPATH, pathseg, path, fd); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); vp = nd.ni_vp; error = kern_readlink_vp(vp, buf, bufseg, count, td); vput(vp); return (error); } /* * Helper function to readlink from a vnode */ static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg, size_t count, struct thread *td) { struct iovec aiov; struct uio auio; int error; ASSERT_VOP_LOCKED(vp, "kern_readlink_vp(): vp not locked"); #ifdef MAC error = mac_vnode_check_readlink(td->td_ucred, vp); if (error != 0) return (error); #endif if (vp->v_type != VLNK && (vp->v_vflag & VV_READLINK) == 0) return (EINVAL); aiov.iov_base = buf; aiov.iov_len = count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_rw = UIO_READ; auio.uio_segflg = bufseg; auio.uio_td = td; auio.uio_resid = count; error = VOP_READLINK(vp, &auio, td->td_ucred); td->td_retval[0] = count - auio.uio_resid; return (error); } /* * Common implementation code for chflags() and fchflags(). */ static int setfflags(struct thread *td, struct vnode *vp, u_long flags) { struct mount *mp; struct vattr vattr; int error; /* We can't support the value matching VNOVAL. */ if (flags == VNOVAL) return (EOPNOTSUPP); /* * Prevent non-root users from setting flags on devices. When * a device is reused, users can retain ownership of the device * if they are allowed to set flags and programs assume that * chown can't fail when done as root. */ if (VN_ISDEV(vp)) { error = priv_check(td, PRIV_VFS_CHFLAGS_DEV); if (error != 0) return (error); } if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) return (error); VATTR_NULL(&vattr); vattr.va_flags = flags; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); #ifdef MAC error = mac_vnode_check_setflags(td->td_ucred, vp, vattr.va_flags); if (error == 0) #endif error = VOP_SETATTR(vp, &vattr, td->td_ucred); VOP_UNLOCK(vp); vn_finished_write(mp); return (error); } /* * Change flags of a file given a path name. */ #ifndef _SYS_SYSPROTO_H_ struct chflags_args { const char *path; u_long flags; }; #endif int sys_chflags(struct thread *td, struct chflags_args *uap) { return (kern_chflagsat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->flags, 0)); } #ifndef _SYS_SYSPROTO_H_ struct chflagsat_args { int fd; const char *path; u_long flags; int atflag; } #endif int sys_chflagsat(struct thread *td, struct chflagsat_args *uap) { return (kern_chflagsat(td, uap->fd, uap->path, UIO_USERSPACE, uap->flags, uap->atflag)); } /* * Same as chflags() but doesn't follow symlinks. */ #ifndef _SYS_SYSPROTO_H_ struct lchflags_args { const char *path; u_long flags; }; #endif int sys_lchflags(struct thread *td, struct lchflags_args *uap) { return (kern_chflagsat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->flags, AT_SYMLINK_NOFOLLOW)); } static int kern_chflagsat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, u_long flags, int atflag) { struct nameidata nd; int error; if ((atflag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH)) != 0) return (EINVAL); AUDIT_ARG_FFLAGS(flags); NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(atflag, AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchflags_rights); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); error = setfflags(td, nd.ni_vp, flags); vrele(nd.ni_vp); return (error); } /* * Change flags of a file given a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct fchflags_args { int fd; u_long flags; }; #endif int sys_fchflags(struct thread *td, struct fchflags_args *uap) { struct file *fp; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_FFLAGS(uap->flags); error = getvnode(td, uap->fd, &cap_fchflags_rights, &fp); if (error != 0) return (error); #ifdef AUDIT if (AUDITING_TD(td)) { vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); AUDIT_ARG_VNODE1(fp->f_vnode); VOP_UNLOCK(fp->f_vnode); } #endif error = setfflags(td, fp->f_vnode, uap->flags); fdrop(fp, td); return (error); } /* * Common implementation code for chmod(), lchmod() and fchmod(). */ int setfmode(struct thread *td, struct ucred *cred, struct vnode *vp, int mode) { struct mount *mp; struct vattr vattr; int error; if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) return (error); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); VATTR_NULL(&vattr); vattr.va_mode = mode & ALLPERMS; #ifdef MAC error = mac_vnode_check_setmode(cred, vp, vattr.va_mode); if (error == 0) #endif error = VOP_SETATTR(vp, &vattr, cred); VOP_UNLOCK(vp); vn_finished_write(mp); return (error); } /* * Change mode of a file given path name. */ #ifndef _SYS_SYSPROTO_H_ struct chmod_args { char *path; int mode; }; #endif int sys_chmod(struct thread *td, struct chmod_args *uap) { return (kern_fchmodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->mode, 0)); } #ifndef _SYS_SYSPROTO_H_ struct fchmodat_args { int dirfd; char *path; mode_t mode; int flag; } #endif int sys_fchmodat(struct thread *td, struct fchmodat_args *uap) { return (kern_fchmodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode, uap->flag)); } /* * Change mode of a file given path name (don't follow links.) */ #ifndef _SYS_SYSPROTO_H_ struct lchmod_args { char *path; int mode; }; #endif int sys_lchmod(struct thread *td, struct lchmod_args *uap) { return (kern_fchmodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->mode, AT_SYMLINK_NOFOLLOW)); } int kern_fchmodat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, mode_t mode, int flag) { struct nameidata nd; int error; if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH)) != 0) return (EINVAL); AUDIT_ARG_MODE(mode); NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchmod_rights); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); error = setfmode(td, td->td_ucred, nd.ni_vp, mode); vrele(nd.ni_vp); return (error); } /* * Change mode of a file given a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct fchmod_args { int fd; int mode; }; #endif int sys_fchmod(struct thread *td, struct fchmod_args *uap) { struct file *fp; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_MODE(uap->mode); error = fget(td, uap->fd, &cap_fchmod_rights, &fp); if (error != 0) return (error); error = fo_chmod(fp, uap->mode, td->td_ucred, td); fdrop(fp, td); return (error); } /* * Common implementation for chown(), lchown(), and fchown() */ int setfown(struct thread *td, struct ucred *cred, struct vnode *vp, uid_t uid, gid_t gid) { struct mount *mp; struct vattr vattr; int error; if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) return (error); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); VATTR_NULL(&vattr); vattr.va_uid = uid; vattr.va_gid = gid; #ifdef MAC error = mac_vnode_check_setowner(cred, vp, vattr.va_uid, vattr.va_gid); if (error == 0) #endif error = VOP_SETATTR(vp, &vattr, cred); VOP_UNLOCK(vp); vn_finished_write(mp); return (error); } /* * Set ownership given a path name. */ #ifndef _SYS_SYSPROTO_H_ struct chown_args { char *path; int uid; int gid; }; #endif int sys_chown(struct thread *td, struct chown_args *uap) { return (kern_fchownat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->uid, uap->gid, 0)); } #ifndef _SYS_SYSPROTO_H_ struct fchownat_args { int fd; const char * path; uid_t uid; gid_t gid; int flag; }; #endif int sys_fchownat(struct thread *td, struct fchownat_args *uap) { return (kern_fchownat(td, uap->fd, uap->path, UIO_USERSPACE, uap->uid, uap->gid, uap->flag)); } int kern_fchownat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, int uid, int gid, int flag) { struct nameidata nd; int error; if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH)) != 0) return (EINVAL); AUDIT_ARG_OWNER(uid, gid); NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchown_rights); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); error = setfown(td, td->td_ucred, nd.ni_vp, uid, gid); vrele(nd.ni_vp); return (error); } /* * Set ownership given a path name, do not cross symlinks. */ #ifndef _SYS_SYSPROTO_H_ struct lchown_args { char *path; int uid; int gid; }; #endif int sys_lchown(struct thread *td, struct lchown_args *uap) { return (kern_fchownat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->uid, uap->gid, AT_SYMLINK_NOFOLLOW)); } /* * Set ownership given a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct fchown_args { int fd; int uid; int gid; }; #endif int sys_fchown(struct thread *td, struct fchown_args *uap) { struct file *fp; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_OWNER(uap->uid, uap->gid); error = fget(td, uap->fd, &cap_fchown_rights, &fp); if (error != 0) return (error); error = fo_chown(fp, uap->uid, uap->gid, td->td_ucred, td); fdrop(fp, td); return (error); } /* * Common implementation code for utimes(), lutimes(), and futimes(). */ static int getutimes(const struct timeval *usrtvp, enum uio_seg tvpseg, struct timespec *tsp) { struct timeval tv[2]; const struct timeval *tvp; int error; if (usrtvp == NULL) { vfs_timestamp(&tsp[0]); tsp[1] = tsp[0]; } else { if (tvpseg == UIO_SYSSPACE) { tvp = usrtvp; } else { if ((error = copyin(usrtvp, tv, sizeof(tv))) != 0) return (error); tvp = tv; } if (tvp[0].tv_usec < 0 || tvp[0].tv_usec >= 1000000 || tvp[1].tv_usec < 0 || tvp[1].tv_usec >= 1000000) return (EINVAL); TIMEVAL_TO_TIMESPEC(&tvp[0], &tsp[0]); TIMEVAL_TO_TIMESPEC(&tvp[1], &tsp[1]); } return (0); } /* * Common implementation code for futimens(), utimensat(). */ #define UTIMENS_NULL 0x1 #define UTIMENS_EXIT 0x2 static int getutimens(const struct timespec *usrtsp, enum uio_seg tspseg, struct timespec *tsp, int *retflags) { struct timespec tsnow; int error; vfs_timestamp(&tsnow); *retflags = 0; if (usrtsp == NULL) { tsp[0] = tsnow; tsp[1] = tsnow; *retflags |= UTIMENS_NULL; return (0); } if (tspseg == UIO_SYSSPACE) { tsp[0] = usrtsp[0]; tsp[1] = usrtsp[1]; } else if ((error = copyin(usrtsp, tsp, sizeof(*tsp) * 2)) != 0) return (error); if (tsp[0].tv_nsec == UTIME_OMIT && tsp[1].tv_nsec == UTIME_OMIT) *retflags |= UTIMENS_EXIT; if (tsp[0].tv_nsec == UTIME_NOW && tsp[1].tv_nsec == UTIME_NOW) *retflags |= UTIMENS_NULL; if (tsp[0].tv_nsec == UTIME_OMIT) tsp[0].tv_sec = VNOVAL; else if (tsp[0].tv_nsec == UTIME_NOW) tsp[0] = tsnow; else if (tsp[0].tv_nsec < 0 || tsp[0].tv_nsec >= 1000000000L) return (EINVAL); if (tsp[1].tv_nsec == UTIME_OMIT) tsp[1].tv_sec = VNOVAL; else if (tsp[1].tv_nsec == UTIME_NOW) tsp[1] = tsnow; else if (tsp[1].tv_nsec < 0 || tsp[1].tv_nsec >= 1000000000L) return (EINVAL); return (0); } /* * Common implementation code for utimes(), lutimes(), futimes(), futimens(), * and utimensat(). */ static int setutimes(struct thread *td, struct vnode *vp, const struct timespec *ts, int numtimes, int nullflag) { struct mount *mp; struct vattr vattr; int error; bool setbirthtime; setbirthtime = false; vattr.va_birthtime.tv_sec = VNOVAL; vattr.va_birthtime.tv_nsec = 0; if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) return (error); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (numtimes < 3 && VOP_GETATTR(vp, &vattr, td->td_ucred) == 0 && timespeccmp(&ts[1], &vattr.va_birthtime, < )) setbirthtime = true; VATTR_NULL(&vattr); vattr.va_atime = ts[0]; vattr.va_mtime = ts[1]; if (setbirthtime) vattr.va_birthtime = ts[1]; if (numtimes > 2) vattr.va_birthtime = ts[2]; if (nullflag) vattr.va_vaflags |= VA_UTIMES_NULL; #ifdef MAC error = mac_vnode_check_setutimes(td->td_ucred, vp, vattr.va_atime, vattr.va_mtime); #endif if (error == 0) error = VOP_SETATTR(vp, &vattr, td->td_ucred); VOP_UNLOCK(vp); vn_finished_write(mp); return (error); } /* * Set the access and modification times of a file. */ #ifndef _SYS_SYSPROTO_H_ struct utimes_args { char *path; struct timeval *tptr; }; #endif int sys_utimes(struct thread *td, struct utimes_args *uap) { return (kern_utimesat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->tptr, UIO_USERSPACE)); } #ifndef _SYS_SYSPROTO_H_ struct futimesat_args { int fd; const char * path; const struct timeval * times; }; #endif int sys_futimesat(struct thread *td, struct futimesat_args *uap) { return (kern_utimesat(td, uap->fd, uap->path, UIO_USERSPACE, uap->times, UIO_USERSPACE)); } int kern_utimesat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, const struct timeval *tptr, enum uio_seg tptrseg) { struct nameidata nd; struct timespec ts[2]; int error; if ((error = getutimes(tptr, tptrseg, ts)) != 0) return (error); NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd, &cap_futimes_rights); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL); vrele(nd.ni_vp); return (error); } /* * Set the access and modification times of a file. */ #ifndef _SYS_SYSPROTO_H_ struct lutimes_args { char *path; struct timeval *tptr; }; #endif int sys_lutimes(struct thread *td, struct lutimes_args *uap) { return (kern_lutimes(td, uap->path, UIO_USERSPACE, uap->tptr, UIO_USERSPACE)); } int kern_lutimes(struct thread *td, const char *path, enum uio_seg pathseg, const struct timeval *tptr, enum uio_seg tptrseg) { struct timespec ts[2]; struct nameidata nd; int error; if ((error = getutimes(tptr, tptrseg, ts)) != 0) return (error); NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, pathseg, path); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL); vrele(nd.ni_vp); return (error); } /* * Set the access and modification times of a file. */ #ifndef _SYS_SYSPROTO_H_ struct futimes_args { int fd; struct timeval *tptr; }; #endif int sys_futimes(struct thread *td, struct futimes_args *uap) { return (kern_futimes(td, uap->fd, uap->tptr, UIO_USERSPACE)); } int kern_futimes(struct thread *td, int fd, const struct timeval *tptr, enum uio_seg tptrseg) { struct timespec ts[2]; struct file *fp; int error; AUDIT_ARG_FD(fd); error = getutimes(tptr, tptrseg, ts); if (error != 0) return (error); error = getvnode(td, fd, &cap_futimes_rights, &fp); if (error != 0) return (error); #ifdef AUDIT if (AUDITING_TD(td)) { vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); AUDIT_ARG_VNODE1(fp->f_vnode); VOP_UNLOCK(fp->f_vnode); } #endif error = setutimes(td, fp->f_vnode, ts, 2, tptr == NULL); fdrop(fp, td); return (error); } int sys_futimens(struct thread *td, struct futimens_args *uap) { return (kern_futimens(td, uap->fd, uap->times, UIO_USERSPACE)); } int kern_futimens(struct thread *td, int fd, const struct timespec *tptr, enum uio_seg tptrseg) { struct timespec ts[2]; struct file *fp; int error, flags; AUDIT_ARG_FD(fd); error = getutimens(tptr, tptrseg, ts, &flags); if (error != 0) return (error); if (flags & UTIMENS_EXIT) return (0); error = getvnode(td, fd, &cap_futimes_rights, &fp); if (error != 0) return (error); #ifdef AUDIT if (AUDITING_TD(td)) { vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); AUDIT_ARG_VNODE1(fp->f_vnode); VOP_UNLOCK(fp->f_vnode); } #endif error = setutimes(td, fp->f_vnode, ts, 2, flags & UTIMENS_NULL); fdrop(fp, td); return (error); } int sys_utimensat(struct thread *td, struct utimensat_args *uap) { return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE, uap->times, UIO_USERSPACE, uap->flag)); } int kern_utimensat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, const struct timespec *tptr, enum uio_seg tptrseg, int flag) { struct nameidata nd; struct timespec ts[2]; int error, flags; if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH)) != 0) return (EINVAL); if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0) return (error); NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH) | AUDITVNODE1, pathseg, path, fd, &cap_futimes_rights); if ((error = namei(&nd)) != 0) return (error); /* * We are allowed to call namei() regardless of 2xUTIME_OMIT. * POSIX states: * "If both tv_nsec fields are UTIME_OMIT... EACCESS may be detected." * "Search permission is denied by a component of the path prefix." */ NDFREE_PNBUF(&nd); if ((flags & UTIMENS_EXIT) == 0) error = setutimes(td, nd.ni_vp, ts, 2, flags & UTIMENS_NULL); vrele(nd.ni_vp); return (error); } /* * Truncate a file given its path name. */ #ifndef _SYS_SYSPROTO_H_ struct truncate_args { char *path; int pad; off_t length; }; #endif int sys_truncate(struct thread *td, struct truncate_args *uap) { return (kern_truncate(td, uap->path, UIO_USERSPACE, uap->length)); } int kern_truncate(struct thread *td, const char *path, enum uio_seg pathseg, off_t length) { struct mount *mp; struct vnode *vp; void *rl_cookie; struct nameidata nd; int error; if (length < 0) return (EINVAL); NDPREINIT(&nd); retry: NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; NDFREE_PNBUF(&nd); rl_cookie = vn_rangelock_wlock(vp, 0, OFF_MAX); if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) { vn_rangelock_unlock(vp, rl_cookie); vrele(vp); return (error); } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (vp->v_type == VDIR) { error = EISDIR; goto out; } #ifdef MAC error = mac_vnode_check_write(td->td_ucred, NOCRED, vp); if (error != 0) goto out; #endif error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td); if (error != 0) goto out; error = vn_truncate_locked(vp, length, false, td->td_ucred); out: VOP_UNLOCK(vp); vn_finished_write(mp); vn_rangelock_unlock(vp, rl_cookie); vrele(vp); if (error == ERELOOKUP) goto retry; return (error); } #if defined(COMPAT_43) /* * Truncate a file given its path name. */ #ifndef _SYS_SYSPROTO_H_ struct otruncate_args { char *path; long length; }; #endif int otruncate(struct thread *td, struct otruncate_args *uap) { return (kern_truncate(td, uap->path, UIO_USERSPACE, uap->length)); } #endif /* COMPAT_43 */ #if defined(COMPAT_FREEBSD6) /* Versions with the pad argument */ int freebsd6_truncate(struct thread *td, struct freebsd6_truncate_args *uap) { return (kern_truncate(td, uap->path, UIO_USERSPACE, uap->length)); } int freebsd6_ftruncate(struct thread *td, struct freebsd6_ftruncate_args *uap) { return (kern_ftruncate(td, uap->fd, uap->length)); } #endif int kern_fsync(struct thread *td, int fd, bool fullsync) { struct vnode *vp; struct mount *mp; struct file *fp; int error; AUDIT_ARG_FD(fd); error = getvnode(td, fd, &cap_fsync_rights, &fp); if (error != 0) return (error); vp = fp->f_vnode; #if 0 if (!fullsync) /* XXXKIB: compete outstanding aio writes */; #endif retry: error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH); if (error != 0) goto drop; vn_lock(vp, vn_lktype_write(mp, vp) | LK_RETRY); AUDIT_ARG_VNODE1(vp); vnode_pager_clean_async(vp); error = fullsync ? VOP_FSYNC(vp, MNT_WAIT, td) : VOP_FDATASYNC(vp, td); VOP_UNLOCK(vp); vn_finished_write(mp); if (error == ERELOOKUP) goto retry; drop: fdrop(fp, td); return (error); } /* * Sync an open file. */ #ifndef _SYS_SYSPROTO_H_ struct fsync_args { int fd; }; #endif int sys_fsync(struct thread *td, struct fsync_args *uap) { return (kern_fsync(td, uap->fd, true)); } int sys_fdatasync(struct thread *td, struct fdatasync_args *uap) { return (kern_fsync(td, uap->fd, false)); } /* * Rename files. Source and destination must either both be directories, or * both not be directories. If target is a directory, it must be empty. */ #ifndef _SYS_SYSPROTO_H_ struct rename_args { char *from; char *to; }; #endif int sys_rename(struct thread *td, struct rename_args *uap) { return (kern_renameat(td, AT_FDCWD, uap->from, AT_FDCWD, uap->to, UIO_USERSPACE)); } #ifndef _SYS_SYSPROTO_H_ struct renameat_args { int oldfd; char *old; int newfd; char *new; }; #endif int sys_renameat(struct thread *td, struct renameat_args *uap) { return (kern_renameat(td, uap->oldfd, uap->old, uap->newfd, uap->new, UIO_USERSPACE)); } #ifdef MAC static int kern_renameat_mac(struct thread *td, int oldfd, const char *old, int newfd, const char *new, enum uio_seg pathseg, struct nameidata *fromnd) { int error; NDINIT_ATRIGHTS(fromnd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1, pathseg, old, oldfd, &cap_renameat_source_rights); if ((error = namei(fromnd)) != 0) return (error); error = mac_vnode_check_rename_from(td->td_ucred, fromnd->ni_dvp, fromnd->ni_vp, &fromnd->ni_cnd); VOP_UNLOCK(fromnd->ni_dvp); if (fromnd->ni_dvp != fromnd->ni_vp) VOP_UNLOCK(fromnd->ni_vp); if (error != 0) { NDFREE_PNBUF(fromnd); vrele(fromnd->ni_dvp); vrele(fromnd->ni_vp); } return (error); } #endif int kern_renameat(struct thread *td, int oldfd, const char *old, int newfd, const char *new, enum uio_seg pathseg) { struct mount *mp, *tmp; struct vnode *tvp, *fvp, *tdvp; struct nameidata fromnd, tond; uint64_t tondflags; int error; short irflag; again: tmp = mp = NULL; bwillwrite(); #ifdef MAC if (mac_vnode_check_rename_from_enabled()) { error = kern_renameat_mac(td, oldfd, old, newfd, new, pathseg, &fromnd); if (error != 0) return (error); } else { #endif NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | AUDITVNODE1, pathseg, old, oldfd, &cap_renameat_source_rights); if ((error = namei(&fromnd)) != 0) return (error); #ifdef MAC } #endif fvp = fromnd.ni_vp; tondflags = LOCKPARENT | LOCKLEAF | NOCACHE | AUDITVNODE2; if (fromnd.ni_vp->v_type == VDIR) tondflags |= WILLBEDIR; NDINIT_ATRIGHTS(&tond, RENAME, tondflags, pathseg, new, newfd, &cap_renameat_target_rights); if ((error = namei(&tond)) != 0) { /* Translate error code for rename("dir1", "dir2/."). */ if (error == EISDIR && fvp->v_type == VDIR) error = EINVAL; NDFREE_PNBUF(&fromnd); vrele(fromnd.ni_dvp); vrele(fvp); goto out1; } tdvp = tond.ni_dvp; tvp = tond.ni_vp; error = vn_start_write(fvp, &mp, V_NOWAIT); if (error != 0) { again1: NDFREE_PNBUF(&fromnd); NDFREE_PNBUF(&tond); if (tvp != NULL) vput(tvp); if (tdvp == tvp) vrele(tdvp); else vput(tdvp); vrele(fromnd.ni_dvp); vrele(fvp); if (tmp != NULL) { lockmgr(&tmp->mnt_renamelock, LK_EXCLUSIVE, NULL); lockmgr(&tmp->mnt_renamelock, LK_RELEASE, NULL); vfs_rel(tmp); tmp = NULL; } error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH); if (error != 0) return (error); goto again; } error = VOP_GETWRITEMOUNT(tdvp, &tmp); if (error != 0 || tmp == NULL) goto again1; error = lockmgr(&tmp->mnt_renamelock, LK_EXCLUSIVE | LK_NOWAIT, NULL); if (error != 0) { vn_finished_write(mp); goto again1; } irflag = vn_irflag_read(fvp); if (((irflag & VIRF_NAMEDATTR) != 0 && tdvp != fromnd.ni_dvp) || (irflag & VIRF_NAMEDDIR) != 0) { error = EINVAL; goto out; } if (tvp != NULL) { if (fvp->v_type == VDIR && tvp->v_type != VDIR) { error = ENOTDIR; goto out; } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { error = EISDIR; goto out; } #ifdef CAPABILITIES if (newfd != AT_FDCWD && (tond.ni_resflags & NIRES_ABS) == 0) { /* * If the target already exists we require CAP_UNLINKAT * from 'newfd', when newfd was used for the lookup. */ error = cap_check(&tond.ni_filecaps.fc_rights, &cap_unlinkat_rights); if (error != 0) goto out; } #endif } if (fvp == tdvp) { error = EINVAL; goto out; } /* * If the source is the same as the destination (that is, if they * are links to the same vnode), then there is nothing to do. */ if (fvp == tvp) error = ERESTART; #ifdef MAC else error = mac_vnode_check_rename_to(td->td_ucred, tdvp, tond.ni_vp, fromnd.ni_dvp == tdvp, &tond.ni_cnd); #endif out: if (error == 0) { error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); NDFREE_PNBUF(&fromnd); NDFREE_PNBUF(&tond); } else { NDFREE_PNBUF(&fromnd); NDFREE_PNBUF(&tond); if (tvp != NULL) vput(tvp); if (tdvp == tvp) vrele(tdvp); else vput(tdvp); vrele(fromnd.ni_dvp); vrele(fvp); } lockmgr(&tmp->mnt_renamelock, LK_RELEASE, 0); vfs_rel(tmp); vn_finished_write(mp); out1: if (error == ERESTART) return (0); if (error == ERELOOKUP) goto again; return (error); } /* * Make a directory file. */ #ifndef _SYS_SYSPROTO_H_ struct mkdir_args { char *path; int mode; }; #endif int sys_mkdir(struct thread *td, struct mkdir_args *uap) { return (kern_mkdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->mode)); } #ifndef _SYS_SYSPROTO_H_ struct mkdirat_args { int fd; char *path; mode_t mode; }; #endif int sys_mkdirat(struct thread *td, struct mkdirat_args *uap) { return (kern_mkdirat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode)); } int kern_mkdirat(struct thread *td, int fd, const char *path, enum uio_seg segflg, int mode) { struct mount *mp; struct vattr vattr; struct nameidata nd; int error; AUDIT_ARG_MODE(mode); NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | AUDITVNODE1 | NC_NOMAKEENTRY | NC_KEEPPOSENTRY | FAILIFEXISTS | WILLBEDIR, segflg, path, fd, &cap_mkdirat_rights); if ((error = namei(&nd)) != 0) return (error); if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { NDFREE_PNBUF(&nd); vput(nd.ni_dvp); if ((error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH)) != 0) return (error); goto restart; } if ((vn_irflag_read(nd.ni_dvp) & VIRF_NAMEDDIR) != 0) { error = EINVAL; goto out; } VATTR_NULL(&vattr); vattr.va_type = VDIR; vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_pd->pd_cmask; #ifdef MAC error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); if (error != 0) goto out; #endif error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); out: NDFREE_PNBUF(&nd); VOP_VPUT_PAIR(nd.ni_dvp, error == 0 ? &nd.ni_vp : NULL, true); vn_finished_write(mp); if (error == ERELOOKUP) goto restart; return (error); } /* * Remove a directory file. */ #ifndef _SYS_SYSPROTO_H_ struct rmdir_args { char *path; }; #endif int sys_rmdir(struct thread *td, struct rmdir_args *uap) { return (kern_frmdirat(td, AT_FDCWD, uap->path, FD_NONE, UIO_USERSPACE, 0)); } int kern_frmdirat(struct thread *td, int dfd, const char *path, int fd, enum uio_seg pathseg, int flag) { struct mount *mp; struct vnode *vp; struct file *fp; struct nameidata nd; cap_rights_t rights; int error; fp = NULL; if (fd != FD_NONE) { error = getvnode(td, fd, cap_rights_init_one(&rights, CAP_LOOKUP), &fp); if (error != 0) return (error); } NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | at2cnpflags(flag, AT_RESOLVE_BENEATH), pathseg, path, dfd, &cap_unlinkat_rights); if ((error = namei(&nd)) != 0) goto fdout; vp = nd.ni_vp; if (vp->v_type != VDIR) { error = ENOTDIR; goto out; } /* * No rmdir "." please. */ if (nd.ni_dvp == vp) { error = EINVAL; goto out; } /* * The root of a mounted filesystem cannot be deleted. */ if (vp->v_vflag & VV_ROOT) { error = EBUSY; goto out; } if (fp != NULL && fp->f_vnode != vp) { if (VN_IS_DOOMED(fp->f_vnode)) error = EBADF; else error = EDEADLK; goto out; } #ifdef MAC error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp, &nd.ni_cnd); if (error != 0) goto out; #endif if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { NDFREE_PNBUF(&nd); vput(vp); if (nd.ni_dvp == vp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); if ((error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH)) != 0) goto fdout; goto restart; } error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); vn_finished_write(mp); out: NDFREE_PNBUF(&nd); vput(vp); if (nd.ni_dvp == vp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); if (error == ERELOOKUP) goto restart; fdout: if (fp != NULL) fdrop(fp, td); return (error); } #if defined(COMPAT_43) || defined(COMPAT_FREEBSD11) int freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int count, long *basep, void (*func)(struct freebsd11_dirent *)) { struct freebsd11_dirent dstdp; struct dirent *dp, *edp; char *dirbuf; off_t base; ssize_t resid, ucount; int error; /* XXX arbitrary sanity limit on `count'. */ count = min(count, 64 * 1024); dirbuf = malloc(count, M_TEMP, M_WAITOK); error = kern_getdirentries(td, fd, dirbuf, count, &base, &resid, UIO_SYSSPACE); if (error != 0) goto done; if (basep != NULL) *basep = base; ucount = 0; for (dp = (struct dirent *)dirbuf, edp = (struct dirent *)&dirbuf[count - resid]; ucount < count && dp < edp; ) { if (dp->d_reclen == 0) break; MPASS(dp->d_reclen >= _GENERIC_DIRLEN(0)); if (dp->d_namlen >= sizeof(dstdp.d_name)) continue; dstdp.d_type = dp->d_type; dstdp.d_namlen = dp->d_namlen; dstdp.d_fileno = dp->d_fileno; /* truncate */ if (dstdp.d_fileno != dp->d_fileno) { switch (ino64_trunc_error) { default: case 0: break; case 1: error = EOVERFLOW; goto done; case 2: dstdp.d_fileno = UINT32_MAX; break; } } dstdp.d_reclen = sizeof(dstdp) - sizeof(dstdp.d_name) + ((dp->d_namlen + 1 + 3) &~ 3); bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen); bzero(dstdp.d_name + dstdp.d_namlen, dstdp.d_reclen - offsetof(struct freebsd11_dirent, d_name) - dstdp.d_namlen); MPASS(dstdp.d_reclen <= dp->d_reclen); MPASS(ucount + dstdp.d_reclen <= count); if (func != NULL) func(&dstdp); error = copyout(&dstdp, ubuf + ucount, dstdp.d_reclen); if (error != 0) break; dp = (struct dirent *)((char *)dp + dp->d_reclen); ucount += dstdp.d_reclen; } done: free(dirbuf, M_TEMP); if (error == 0) td->td_retval[0] = ucount; return (error); } #endif /* COMPAT */ #ifdef COMPAT_43 static void ogetdirentries_cvt(struct freebsd11_dirent *dp) { #if (BYTE_ORDER == LITTLE_ENDIAN) /* * The expected low byte of dp->d_namlen is our dp->d_type. * The high MBZ byte of dp->d_namlen is our dp->d_namlen. */ dp->d_type = dp->d_namlen; dp->d_namlen = 0; #else /* * The dp->d_type is the high byte of the expected dp->d_namlen, * so must be zero'ed. */ dp->d_type = 0; #endif } /* * Read a block of directory entries in a filesystem independent format. */ #ifndef _SYS_SYSPROTO_H_ struct ogetdirentries_args { int fd; char *buf; u_int count; long *basep; }; #endif int ogetdirentries(struct thread *td, struct ogetdirentries_args *uap) { long loff; int error; error = kern_ogetdirentries(td, uap, &loff); if (error == 0) error = copyout(&loff, uap->basep, sizeof(long)); return (error); } int kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap, long *ploff) { long base; int error; /* XXX arbitrary sanity limit on `count'. */ if (uap->count > 64 * 1024) return (EINVAL); error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base, ogetdirentries_cvt); if (error == 0 && uap->basep != NULL) error = copyout(&base, uap->basep, sizeof(long)); return (error); } #endif /* COMPAT_43 */ #if defined(COMPAT_FREEBSD11) #ifndef _SYS_SYSPROTO_H_ struct freebsd11_getdirentries_args { int fd; char *buf; u_int count; long *basep; }; #endif int freebsd11_getdirentries(struct thread *td, struct freebsd11_getdirentries_args *uap) { long base; int error; error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base, NULL); if (error == 0 && uap->basep != NULL) error = copyout(&base, uap->basep, sizeof(long)); return (error); } int freebsd11_getdents(struct thread *td, struct freebsd11_getdents_args *uap) { struct freebsd11_getdirentries_args ap; ap.fd = uap->fd; ap.buf = uap->buf; ap.count = uap->count; ap.basep = NULL; return (freebsd11_getdirentries(td, &ap)); } #endif /* COMPAT_FREEBSD11 */ /* * Read a block of directory entries in a filesystem independent format. */ int sys_getdirentries(struct thread *td, struct getdirentries_args *uap) { off_t base; int error; error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base, NULL, UIO_USERSPACE); if (error != 0) return (error); if (uap->basep != NULL) error = copyout(&base, uap->basep, sizeof(off_t)); return (error); } int kern_getdirentries(struct thread *td, int fd, char *buf, size_t count, off_t *basep, ssize_t *residp, enum uio_seg bufseg) { struct vnode *vp; struct file *fp; struct uio auio; struct iovec aiov; off_t loff; int error, eofflag; off_t foffset; AUDIT_ARG_FD(fd); if (count > IOSIZE_MAX) return (EINVAL); auio.uio_resid = count; error = getvnode(td, fd, &cap_read_rights, &fp); if (error != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); return (EBADF); } vp = fp->f_vnode; foffset = foffset_lock(fp, 0); unionread: if (__predict_false((vp->v_vflag & VV_UNLINKED) != 0)) { error = ENOENT; goto fail; } aiov.iov_base = buf; aiov.iov_len = count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_READ; auio.uio_segflg = bufseg; auio.uio_td = td; vn_lock(vp, LK_SHARED | LK_RETRY); /* * We want to return ENOTDIR for anything that is not VDIR, but * not for VBAD, and we can't check for VBAD while the vnode is * unlocked. */ if (vp->v_type != VDIR) { if (vp->v_type == VBAD) error = EBADF; else error = ENOTDIR; VOP_UNLOCK(vp); goto fail; } AUDIT_ARG_VNODE1(vp); loff = auio.uio_offset = foffset; #ifdef MAC error = mac_vnode_check_readdir(td->td_ucred, vp); if (error == 0) #endif error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); foffset = auio.uio_offset; if (error != 0) { VOP_UNLOCK(vp); goto fail; } if (count == auio.uio_resid && (vp->v_vflag & VV_ROOT) && (vp->v_mount->mnt_flag & MNT_UNION)) { struct vnode *tvp = vp; vp = vp->v_mount->mnt_vnodecovered; - VREF(vp); + vref(vp); fp->f_vnode = vp; foffset = 0; vput(tvp); goto unionread; } VOP_UNLOCK(vp); *basep = loff; if (residp != NULL) *residp = auio.uio_resid; td->td_retval[0] = count - auio.uio_resid; fail: foffset_unlock(fp, foffset, 0); fdrop(fp, td); return (error); } /* * Set the mode mask for creation of filesystem nodes. */ #ifndef _SYS_SYSPROTO_H_ struct umask_args { int newmask; }; #endif int sys_umask(struct thread *td, struct umask_args *uap) { struct pwddesc *pdp; pdp = td->td_proc->p_pd; PWDDESC_XLOCK(pdp); td->td_retval[0] = pdp->pd_cmask; pdp->pd_cmask = uap->newmask & ALLPERMS; PWDDESC_XUNLOCK(pdp); return (0); } /* * Void all references to file by ripping underlying filesystem away from * vnode. */ #ifndef _SYS_SYSPROTO_H_ struct revoke_args { char *path; }; #endif int sys_revoke(struct thread *td, struct revoke_args *uap) { struct vnode *vp; struct vattr vattr; struct nameidata nd; int error; NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, uap->path); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; NDFREE_PNBUF(&nd); if (vp->v_type != VCHR || vp->v_rdev == NULL) { error = EINVAL; goto out; } #ifdef MAC error = mac_vnode_check_revoke(td->td_ucred, vp); if (error != 0) goto out; #endif error = VOP_GETATTR(vp, &vattr, td->td_ucred); if (error != 0) goto out; if (td->td_ucred->cr_uid != vattr.va_uid) { error = priv_check(td, PRIV_VFS_ADMIN); if (error != 0) goto out; } if (devfs_usecount(vp) > 0) VOP_REVOKE(vp, REVOKEALL); out: vput(vp); return (error); } /* * This variant of getvnode() allows O_PATH files. Caller should * ensure that returned file and vnode are only used for compatible * semantics. */ int getvnode_path(struct thread *td, int fd, const cap_rights_t *rightsp, uint8_t *flagsp, struct file **fpp) { struct file *fp; int error; error = fget_unlocked_flags(td, fd, rightsp, flagsp, &fp); if (error != 0) return (error); /* * The file could be not of the vnode type, or it may be not * yet fully initialized, in which case the f_vnode pointer * may be set, but f_ops is still badfileops. E.g., * devfs_open() transiently create such situation to * facilitate csw d_fdopen(). * * Dupfdopen() handling in kern_openat() installs the * half-baked file into the process descriptor table, allowing * other thread to dereference it. Guard against the race by * checking f_ops. */ if (__predict_false(fp->f_vnode == NULL || fp->f_ops == &badfileops)) { fdrop(fp, td); *fpp = NULL; return (EINVAL); } *fpp = fp; return (0); } /* * Convert a user file descriptor to a kernel file entry and check * that, if it is a capability, the correct rights are present. * A reference on the file entry is held upon returning. */ int getvnode(struct thread *td, int fd, const cap_rights_t *rightsp, struct file **fpp) { int error; error = getvnode_path(td, fd, rightsp, NULL, fpp); if (__predict_false(error != 0)) return (error); /* * Filter out O_PATH file descriptors, most getvnode() callers * do not call fo_ methods. */ if (__predict_false((*fpp)->f_ops == &path_fileops)) { fdrop(*fpp, td); *fpp = NULL; error = EBADF; } return (error); } /* * Get an (NFS) file handle. */ #ifndef _SYS_SYSPROTO_H_ struct lgetfh_args { char *fname; fhandle_t *fhp; }; #endif int sys_lgetfh(struct thread *td, struct lgetfh_args *uap) { return (kern_getfhat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->fname, UIO_USERSPACE, uap->fhp, UIO_USERSPACE)); } #ifndef _SYS_SYSPROTO_H_ struct getfh_args { char *fname; fhandle_t *fhp; }; #endif int sys_getfh(struct thread *td, struct getfh_args *uap) { return (kern_getfhat(td, 0, AT_FDCWD, uap->fname, UIO_USERSPACE, uap->fhp, UIO_USERSPACE)); } /* * syscall for the rpc.lockd to use to translate an open descriptor into * a NFS file handle. * * warning: do not remove the priv_check() call or this becomes one giant * security hole. */ #ifndef _SYS_SYSPROTO_H_ struct getfhat_args { int fd; char *path; fhandle_t *fhp; int flags; }; #endif int sys_getfhat(struct thread *td, struct getfhat_args *uap) { return (kern_getfhat(td, uap->flags, uap->fd, uap->path, UIO_USERSPACE, uap->fhp, UIO_USERSPACE)); } int kern_getfhat(struct thread *td, int flags, int fd, const char *path, enum uio_seg pathseg, fhandle_t *fhp, enum uio_seg fhseg) { struct nameidata nd; fhandle_t fh; struct vnode *vp; int error; if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0) return (EINVAL); error = priv_check(td, PRIV_VFS_GETFH); if (error != 0) return (error); NDINIT_AT(&nd, LOOKUP, at2cnpflags(flags, AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH) | LOCKLEAF | AUDITVNODE1, pathseg, path, fd); error = namei(&nd); if (error != 0) return (error); NDFREE_PNBUF(&nd); vp = nd.ni_vp; bzero(&fh, sizeof(fh)); fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; error = VOP_VPTOFH(vp, &fh.fh_fid); vput(vp); if (error == 0) { if (fhseg == UIO_USERSPACE) error = copyout(&fh, fhp, sizeof (fh)); else memcpy(fhp, &fh, sizeof(fh)); } return (error); } #ifndef _SYS_SYSPROTO_H_ struct fhlink_args { fhandle_t *fhp; const char *to; }; #endif int sys_fhlink(struct thread *td, struct fhlink_args *uap) { return (kern_fhlinkat(td, AT_FDCWD, uap->to, UIO_USERSPACE, uap->fhp)); } #ifndef _SYS_SYSPROTO_H_ struct fhlinkat_args { fhandle_t *fhp; int tofd; const char *to; }; #endif int sys_fhlinkat(struct thread *td, struct fhlinkat_args *uap) { return (kern_fhlinkat(td, uap->tofd, uap->to, UIO_USERSPACE, uap->fhp)); } static int kern_fhlinkat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, fhandle_t *fhp) { fhandle_t fh; struct mount *mp; struct vnode *vp; int error; error = priv_check(td, PRIV_VFS_GETFH); if (error != 0) return (error); error = copyin(fhp, &fh, sizeof(fh)); if (error != 0) return (error); do { bwillwrite(); if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL) return (ESTALE); error = VFS_FHTOVP(mp, &fh.fh_fid, LK_SHARED, &vp); vfs_unbusy(mp); if (error != 0) return (error); VOP_UNLOCK(vp); error = kern_linkat_vp(td, vp, fd, path, pathseg); } while (error == EAGAIN || error == ERELOOKUP); return (error); } #ifndef _SYS_SYSPROTO_H_ struct fhreadlink_args { fhandle_t *fhp; char *buf; size_t bufsize; }; #endif int sys_fhreadlink(struct thread *td, struct fhreadlink_args *uap) { fhandle_t fh; struct mount *mp; struct vnode *vp; int error; error = priv_check(td, PRIV_VFS_GETFH); if (error != 0) return (error); if (uap->bufsize > IOSIZE_MAX) return (EINVAL); error = copyin(uap->fhp, &fh, sizeof(fh)); if (error != 0) return (error); if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL) return (ESTALE); error = VFS_FHTOVP(mp, &fh.fh_fid, LK_SHARED, &vp); vfs_unbusy(mp); if (error != 0) return (error); error = kern_readlink_vp(vp, uap->buf, UIO_USERSPACE, uap->bufsize, td); vput(vp); return (error); } /* * syscall for the rpc.lockd to use to translate a NFS file handle into an * open descriptor. * * warning: do not remove the priv_check() call or this becomes one giant * security hole. */ #ifndef _SYS_SYSPROTO_H_ struct fhopen_args { const struct fhandle *u_fhp; int flags; }; #endif int sys_fhopen(struct thread *td, struct fhopen_args *uap) { return (kern_fhopen(td, uap->u_fhp, uap->flags)); } int kern_fhopen(struct thread *td, const struct fhandle *u_fhp, int flags) { struct mount *mp; struct vnode *vp; struct fhandle fhp; struct file *fp; int error, indx; bool named_attr; error = priv_check(td, PRIV_VFS_FHOPEN); if (error != 0) return (error); indx = -1; if ((flags & O_CREAT) != 0) return (EINVAL); error = openflags(&flags); if (error != 0) return (error); error = copyin(u_fhp, &fhp, sizeof(fhp)); if (error != 0) return (error); /* find the mount point */ mp = vfs_busyfs(&fhp.fh_fsid); if (mp == NULL) return (ESTALE); /* now give me my vnode, it gets returned to me locked */ error = VFS_FHTOVP(mp, &fhp.fh_fid, LK_EXCLUSIVE, &vp); vfs_unbusy(mp); if (error != 0) return (error); /* * Check to see if the file handle refers to a named attribute * directory or attribute. If it does, the O_NAMEDATTR flag * must have been specified. */ named_attr = (vn_irflag_read(vp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0; if ((named_attr && (flags & O_NAMEDATTR) == 0) || (!named_attr && (flags & O_NAMEDATTR) != 0)) { vput(vp); return (ENOATTR); } error = falloc_noinstall(td, &fp); if (error != 0) { vput(vp); return (error); } /* Set the flags early so the finit in devfs can pick them up. */ fp->f_flag = flags & FMASK; #ifdef INVARIANTS td->td_dupfd = -1; #endif error = vn_open_vnode(vp, flags, td->td_ucred, td, fp); if (error != 0) { KASSERT(fp->f_ops == &badfileops, ("VOP_OPEN in fhopen() set f_ops")); KASSERT(td->td_dupfd < 0, ("fhopen() encountered fdopen()")); vput(vp); goto bad; } #ifdef INVARIANTS td->td_dupfd = 0; #endif finit_open(fp, vp, flags); VOP_UNLOCK(vp); if ((flags & O_TRUNC) != 0) { error = fo_truncate(fp, 0, td->td_ucred, td); if (error != 0) goto bad; } error = finstall(td, fp, &indx, flags, NULL); bad: fdrop(fp, td); td->td_retval[0] = indx; return (error); } /* * Stat an (NFS) file handle. */ #ifndef _SYS_SYSPROTO_H_ struct fhstat_args { struct fhandle *u_fhp; struct stat *sb; }; #endif int sys_fhstat(struct thread *td, struct fhstat_args *uap) { struct stat sb; struct fhandle fh; int error; error = copyin(uap->u_fhp, &fh, sizeof(fh)); if (error != 0) return (error); error = kern_fhstat(td, fh, &sb); if (error == 0) error = copyout(&sb, uap->sb, sizeof(sb)); return (error); } int kern_fhstat(struct thread *td, struct fhandle fh, struct stat *sb) { struct mount *mp; struct vnode *vp; int error; error = priv_check(td, PRIV_VFS_FHSTAT); if (error != 0) return (error); if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL) return (ESTALE); error = VFS_FHTOVP(mp, &fh.fh_fid, LK_EXCLUSIVE, &vp); vfs_unbusy(mp); if (error != 0) return (error); error = VOP_STAT(vp, sb, td->td_ucred, NOCRED); vput(vp); return (error); } /* * Implement fstatfs() for (NFS) file handles. */ #ifndef _SYS_SYSPROTO_H_ struct fhstatfs_args { struct fhandle *u_fhp; struct statfs *buf; }; #endif int sys_fhstatfs(struct thread *td, struct fhstatfs_args *uap) { struct statfs *sfp; fhandle_t fh; int error; error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); if (error != 0) return (error); sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); error = kern_fhstatfs(td, fh, sfp); if (error == 0) error = copyout(sfp, uap->buf, sizeof(*sfp)); free(sfp, M_STATFS); return (error); } int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) { struct mount *mp; struct vnode *vp; int error; error = priv_check(td, PRIV_VFS_FHSTATFS); if (error != 0) return (error); if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL) return (ESTALE); error = VFS_FHTOVP(mp, &fh.fh_fid, LK_EXCLUSIVE, &vp); if (error != 0) { vfs_unbusy(mp); return (error); } vput(vp); error = prison_canseemount(td->td_ucred, mp); if (error != 0) goto out; #ifdef MAC error = mac_mount_check_stat(td->td_ucred, mp); if (error != 0) goto out; #endif error = VFS_STATFS(mp, buf); out: vfs_unbusy(mp); return (error); } /* * Unlike madvise(2), we do not make a best effort to remember every * possible caching hint. Instead, we remember the last setting with * the exception that we will allow POSIX_FADV_NORMAL to adjust the * region of any current setting. */ int kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len, int advice) { struct fadvise_info *fa, *new; struct file *fp; struct vnode *vp; off_t end; int error; if (offset < 0 || len < 0 || offset > OFF_MAX - len) return (EINVAL); AUDIT_ARG_VALUE(advice); switch (advice) { case POSIX_FADV_SEQUENTIAL: case POSIX_FADV_RANDOM: case POSIX_FADV_NOREUSE: new = malloc(sizeof(*fa), M_FADVISE, M_WAITOK); break; case POSIX_FADV_NORMAL: case POSIX_FADV_WILLNEED: case POSIX_FADV_DONTNEED: new = NULL; break; default: return (EINVAL); } /* XXX: CAP_POSIX_FADVISE? */ AUDIT_ARG_FD(fd); error = fget(td, fd, &cap_no_rights, &fp); if (error != 0) goto out; AUDIT_ARG_FILE(td->td_proc, fp); if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) { error = ESPIPE; goto out; } if (fp->f_type != DTYPE_VNODE) { error = ENODEV; goto out; } vp = fp->f_vnode; if (vp->v_type != VREG) { error = ENODEV; goto out; } if (len == 0) end = OFF_MAX; else end = offset + len - 1; switch (advice) { case POSIX_FADV_SEQUENTIAL: case POSIX_FADV_RANDOM: case POSIX_FADV_NOREUSE: /* * Try to merge any existing non-standard region with * this new region if possible, otherwise create a new * non-standard region for this request. */ mtx_pool_lock(mtxpool_sleep, fp); fa = fp->f_advice; if (fa != NULL && fa->fa_advice == advice && ((fa->fa_start <= end && fa->fa_end >= offset) || (end != OFF_MAX && fa->fa_start == end + 1) || (fa->fa_end != OFF_MAX && fa->fa_end + 1 == offset))) { if (offset < fa->fa_start) fa->fa_start = offset; if (end > fa->fa_end) fa->fa_end = end; } else { new->fa_advice = advice; new->fa_start = offset; new->fa_end = end; fp->f_advice = new; new = fa; } mtx_pool_unlock(mtxpool_sleep, fp); break; case POSIX_FADV_NORMAL: /* * If a the "normal" region overlaps with an existing * non-standard region, trim or remove the * non-standard region. */ mtx_pool_lock(mtxpool_sleep, fp); fa = fp->f_advice; if (fa != NULL) { if (offset <= fa->fa_start && end >= fa->fa_end) { new = fa; fp->f_advice = NULL; } else if (offset <= fa->fa_start && end >= fa->fa_start) fa->fa_start = end + 1; else if (offset <= fa->fa_end && end >= fa->fa_end) fa->fa_end = offset - 1; else if (offset >= fa->fa_start && end <= fa->fa_end) { /* * If the "normal" region is a middle * portion of the existing * non-standard region, just remove * the whole thing rather than picking * one side or the other to * preserve. */ new = fa; fp->f_advice = NULL; } } mtx_pool_unlock(mtxpool_sleep, fp); break; case POSIX_FADV_WILLNEED: case POSIX_FADV_DONTNEED: error = VOP_ADVISE(vp, offset, end, advice); break; } out: if (fp != NULL) fdrop(fp, td); free(new, M_FADVISE); return (error); } int sys_posix_fadvise(struct thread *td, struct posix_fadvise_args *uap) { int error; error = kern_posix_fadvise(td, uap->fd, uap->offset, uap->len, uap->advice); return (kern_posix_error(td, error)); } int kern_copy_file_range(struct thread *td, int infd, off_t *inoffp, int outfd, off_t *outoffp, size_t len, unsigned int flags) { struct file *infp, *infp1, *outfp, *outfp1; struct vnode *invp, *outvp; int error; size_t retlen; void *rl_rcookie, *rl_wcookie; off_t inoff, outoff, savinoff, savoutoff; bool foffsets_locked, foffsets_set; infp = outfp = NULL; rl_rcookie = rl_wcookie = NULL; foffsets_locked = false; foffsets_set = false; error = 0; retlen = 0; if ((flags & ~COPY_FILE_RANGE_USERFLAGS) != 0) { error = EINVAL; goto out; } if (len > SSIZE_MAX) /* * Although the len argument is size_t, the return argument * is ssize_t (which is signed). Therefore a size that won't * fit in ssize_t can't be returned. */ len = SSIZE_MAX; /* Get the file structures for the file descriptors. */ error = fget_read(td, infd, inoffp != NULL ? &cap_pread_rights : &cap_read_rights, &infp); if (error != 0) goto out; if (infp->f_ops == &badfileops) { error = EBADF; goto out; } if (infp->f_vnode == NULL) { error = EINVAL; goto out; } error = fget_write(td, outfd, outoffp != NULL ? &cap_pwrite_rights : &cap_write_rights, &outfp); if (error != 0) goto out; if (outfp->f_ops == &badfileops) { error = EBADF; goto out; } if (outfp->f_vnode == NULL) { error = EINVAL; goto out; } /* * Figure out which file offsets we're reading from and writing to. * If the offsets come from the file descriptions, we need to lock them, * and locking both offsets requires a loop to avoid deadlocks. */ infp1 = outfp1 = NULL; if (inoffp != NULL) inoff = *inoffp; else infp1 = infp; if (outoffp != NULL) outoff = *outoffp; else outfp1 = outfp; if (infp1 != NULL || outfp1 != NULL) { if (infp1 == outfp1) { /* * Overlapping ranges are not allowed. A more thorough * check appears below, but we must not lock the same * offset twice. */ error = EINVAL; goto out; } foffset_lock_pair(infp1, &inoff, outfp1, &outoff, 0); foffsets_locked = true; } else { foffsets_set = true; } savinoff = inoff; savoutoff = outoff; invp = infp->f_vnode; outvp = outfp->f_vnode; /* Sanity check the f_flag bits. */ if ((outfp->f_flag & (FWRITE | FAPPEND)) != FWRITE || (infp->f_flag & FREAD) == 0) { error = EBADF; goto out; } /* If len == 0, just return 0. */ if (len == 0) goto out; /* * Make sure that the ranges we check and lock below are valid. Note * that len is clamped to SSIZE_MAX above. */ if (inoff < 0 || outoff < 0) { error = EINVAL; goto out; } /* * If infp and outfp refer to the same file, the byte ranges cannot * overlap. */ if (invp == outvp) { if ((inoff <= outoff && inoff + len > outoff) || (inoff > outoff && outoff + len > inoff)) { error = EINVAL; goto out; } rangelock_may_recurse(&invp->v_rl); } /* Range lock the byte ranges for both invp and outvp. */ for (;;) { rl_wcookie = vn_rangelock_wlock(outvp, outoff, outoff + len); rl_rcookie = vn_rangelock_tryrlock(invp, inoff, inoff + len); if (rl_rcookie != NULL) break; vn_rangelock_unlock(outvp, rl_wcookie); rl_rcookie = vn_rangelock_rlock(invp, inoff, inoff + len); vn_rangelock_unlock(invp, rl_rcookie); } retlen = len; error = vn_copy_file_range(invp, &inoff, outvp, &outoff, &retlen, flags, infp->f_cred, outfp->f_cred, td); out: if (rl_rcookie != NULL) vn_rangelock_unlock(invp, rl_rcookie); if (rl_wcookie != NULL) vn_rangelock_unlock(outvp, rl_wcookie); if ((foffsets_locked || foffsets_set) && (error == EINTR || error == ERESTART)) { inoff = savinoff; outoff = savoutoff; } if (foffsets_locked) { if (inoffp == NULL) foffset_unlock(infp, inoff, 0); else *inoffp = inoff; if (outoffp == NULL) foffset_unlock(outfp, outoff, 0); else *outoffp = outoff; } else if (foffsets_set) { *inoffp = inoff; *outoffp = outoff; } if (outfp != NULL) fdrop(outfp, td); if (infp != NULL) fdrop(infp, td); td->td_retval[0] = retlen; return (error); } int sys_copy_file_range(struct thread *td, struct copy_file_range_args *uap) { off_t inoff, outoff, *inoffp, *outoffp; int error; inoffp = outoffp = NULL; if (uap->inoffp != NULL) { error = copyin(uap->inoffp, &inoff, sizeof(off_t)); if (error != 0) return (error); inoffp = &inoff; } if (uap->outoffp != NULL) { error = copyin(uap->outoffp, &outoff, sizeof(off_t)); if (error != 0) return (error); outoffp = &outoff; } error = kern_copy_file_range(td, uap->infd, inoffp, uap->outfd, outoffp, uap->len, uap->flags); if (error == 0 && uap->inoffp != NULL) error = copyout(inoffp, uap->inoffp, sizeof(off_t)); if (error == 0 && uap->outoffp != NULL) error = copyout(outoffp, uap->outoffp, sizeof(off_t)); return (error); } diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 85d263dedfb0..6d50583dc1b3 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -1,1256 +1,1254 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. */ #ifndef _SYS_VNODE_H_ #define _SYS_VNODE_H_ #include #include #include #include #include #include #include #include #include #include #include /* * The vnode is the focus of all file activity in UNIX. There is a * unique vnode allocated for each active file, each current directory, * each mounted-on file, text file, and the root. */ /* * Vnode types. VNON means no type. */ __enum_uint8_decl(vtype) { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD, VMARKER, 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, VSTATE_DESTROYING, VSTATE_DEAD, VLASTSTATE = VSTATE_DEAD, }; enum vgetstate { VGET_NONE, VGET_HOLDCNT, VGET_USECOUNT, }; /* * Each underlying filesystem allocates its own private area and hangs * it from v_data. If non-null, this area is freed in getnewvnode(). */ struct cache_fpl; struct inotify_watch; struct namecache; struct vpollinfo { struct mtx vpi_lock; /* lock to protect below */ TAILQ_HEAD(, inotify_watch) vpi_inotify; /* list of inotify watchers */ struct selinfo vpi_selinfo; /* identity of poller(s) */ short vpi_events; /* what they are looking for */ short vpi_revents; /* what has happened */ }; /* * Reading or writing any of these items requires holding the appropriate lock. * * Lock reference: * c - namecache mutex * i - interlock * l - mp mnt_listmtx or freelist mutex * I - updated with atomics, 0->1 and 1->0 transitions with interlock held * m - mount point interlock * p - pollinfo lock * u - Only a reference to the vnode is needed to read. * v - vnode lock * * Vnodes may be found on many lists. The general way to deal with operating * on a vnode that is on a list is: * 1) Lock the list and find the vnode. * 2) Lock interlock so that the vnode does not go away. * 3) Unlock the list to avoid lock order reversals. * 4) vget with LK_INTERLOCK and check for ENOENT, or * 5) Check for DOOMED if the vnode lock is not required. * 6) Perform your operation, then vput(). */ #if defined(_KERNEL) || defined(_KVM_VNODE) struct vnode { /* * Fields which define the identity of the vnode. These fields are * owned by the filesystem (XXX: and vgone() ?) */ __enum_uint8(vtype) v_type; /* u vnode type */ __enum_uint8(vstate) v_state; /* u vnode state */ short v_irflag; /* i frequently read flags */ seqc_t v_seqc; /* i modification count */ uint32_t v_nchash; /* u namecache hash */ u_int v_hash; const struct vop_vector *v_op; /* u vnode operations vector */ void *v_data; /* u private data for fs */ /* * Filesystem instance stuff */ struct mount *v_mount; /* u ptr to vfs we are in */ TAILQ_ENTRY(vnode) v_nmntvnodes; /* m vnodes for mount point */ /* * Type specific fields, only one applies to any given vnode. */ union { struct mount *v_mountedhere; /* v ptr to mountpoint (VDIR) */ struct unpcb *v_unpcb; /* v unix domain net (VSOCK) */ struct cdev *v_rdev; /* v device (VCHR, VBLK) */ struct fifoinfo *v_fifoinfo; /* v fifo (VFIFO) */ }; /* * vfs_hash: (mount + inode) -> vnode hash. The hash value * itself is grouped with other int fields, to avoid padding. */ LIST_ENTRY(vnode) v_hashlist; /* * VFS_namecache stuff */ LIST_HEAD(, namecache) v_cache_src; /* c Cache entries from us */ TAILQ_HEAD(, namecache) v_cache_dst; /* c Cache entries to us */ struct namecache *v_cache_dd; /* c Cache entry for .. vnode */ /* * Locking */ struct lock v_lock; /* u (if fs don't have one) */ struct mtx v_interlock; /* lock for "i" things */ struct lock *v_vnlock; /* u pointer to vnode lock */ /* * The machinery of being a vnode */ TAILQ_ENTRY(vnode) v_vnodelist; /* l vnode lists */ TAILQ_ENTRY(vnode) v_lazylist; /* l vnode lazy list */ struct bufobj v_bufobj; /* * Buffer cache object */ /* * Hooks for various subsystems and features. */ struct vpollinfo *v_pollinfo; /* i Poll events, p for *v_pi */ struct label *v_label; /* MAC label for vnode */ struct lockf *v_lockf; /* Byte-level advisory lock list */ struct rangelock v_rl; /* Byte-range lock */ u_int v_holdcnt; /* I prevents recycling. */ u_int v_usecount; /* I ref count of users */ u_short v_iflag; /* i vnode flags (see below) */ u_short v_vflag; /* v vnode flags */ u_short v_mflag; /* l mnt-specific vnode flags */ short v_dbatchcpu; /* i LRU requeue deferral batch */ int v_writecount; /* I ref count of writers or (negative) text users */ int v_seqc_users; /* i modifications pending */ }; #define VN_ISDEV(vp) VTYPE_ISDEV((vp)->v_type) #ifndef DEBUG_LOCKS #ifdef _LP64 /* * Not crossing 448 bytes fits 9 vnodes per page. If you have to add fields * to the structure and there is nothing which can be done to prevent growth * then so be it. But don't grow it without a good reason. */ _Static_assert(sizeof(struct vnode) <= 448, "vnode size crosses 448 bytes"); #endif #endif #endif /* defined(_KERNEL) || defined(_KVM_VNODE) */ #define bo2vnode(bo) __containerof((bo), struct vnode, v_bufobj) /* XXX: These are temporary to avoid a source sweep at this time */ #define v_object v_bufobj.bo_object /* We don't need to lock the knlist */ #define VN_KNLIST_EMPTY(vp) ((vp)->v_pollinfo == NULL || \ KNLIST_EMPTY(&(vp)->v_pollinfo->vpi_selinfo.si_note)) #define VN_KNOTE(vp, b, a) \ do { \ if (!VN_KNLIST_EMPTY(vp)) \ KNOTE(&vp->v_pollinfo->vpi_selinfo.si_note, (b), \ (a) | KNF_NOKQLOCK); \ } while (0) #define VN_KNOTE_LOCKED(vp, b) VN_KNOTE(vp, b, KNF_LISTLOCKED) #define VN_KNOTE_UNLOCKED(vp, b) VN_KNOTE(vp, b, 0) /* * Vnode flags. * VI flags are protected by interlock and live in v_iflag * VIRF flags are protected by interlock and live in v_irflag * VV flags are protected by the vnode lock and live in v_vflag * * VIRF_DOOMED is doubly protected by the interlock and vnode lock. Both * are required for writing but the status may be checked with either. */ #define VHOLD_NO_SMR (1<<29) /* Disable vhold_smr */ #define VHOLD_ALL_FLAGS (VHOLD_NO_SMR) #define VIRF_DOOMED 0x0001 /* This vnode is being recycled */ #define VIRF_PGREAD 0x0002 /* Direct reads from the page cache are permitted, never cleared once set */ #define VIRF_MOUNTPOINT 0x0004 /* This vnode is mounted on */ #define VIRF_TEXT_REF 0x0008 /* Executable mappings ref the vnode */ #define VIRF_CROSSMP 0x0010 /* Cross-mp vnode, no locking */ #define VIRF_NAMEDDIR 0x0020 /* Named attribute directory */ #define VIRF_NAMEDATTR 0x0040 /* Named attribute */ #define VIRF_INOTIFY 0x0080 /* This vnode is being watched */ #define VIRF_INOTIFY_PARENT 0x0100 /* A parent of this vnode may be being watched */ #define VI_UNUSED0 0x0001 /* unused */ #define VI_MOUNT 0x0002 /* Mount in progress */ #define VI_DOINGINACT 0x0004 /* VOP_INACTIVE is in progress */ #define VI_OWEINACT 0x0008 /* Need to call inactive */ #define VI_DEFINACT 0x0010 /* deferred inactive */ #define VI_FOPENING 0x0020 /* In open, with opening process having the first right to advlock file */ #define VV_ROOT 0x0001 /* root of its filesystem */ #define VV_ISTTY 0x0002 /* vnode represents a tty */ #define VV_NOSYNC 0x0004 /* unlinked, stop syncing */ #define VV_ETERNALDEV 0x0008 /* device that is never destroyed */ #define VV_CACHEDLABEL 0x0010 /* Vnode has valid cached MAC label */ #define VV_VMSIZEVNLOCK 0x0020 /* object size check requires vnode lock */ #define VV_COPYONWRITE 0x0040 /* vnode is doing copy-on-write */ #define VV_SYSTEM 0x0080 /* vnode being used by kernel */ #define VV_PROCDEP 0x0100 /* vnode is process dependent */ #define VV_UNLINKED 0x0200 /* unlinked but stil open directory */ #define VV_DELETED 0x0400 /* should be removed */ #define VV_MD 0x0800 /* vnode backs the md device */ #define VV_FORCEINSMQ 0x1000 /* force the insmntque to succeed */ #define VV_READLINK 0x2000 /* fdescfs linux vnode */ #define VV_UNREF 0x4000 /* vunref, do not drop lock in inactive() */ #define VV_CROSSLOCK 0x8000 /* vnode lock is shared w/ root mounted here */ #define VMP_LAZYLIST 0x0001 /* Vnode is on mnt's lazy list */ /* * Vnode attributes. A field value of VNOVAL represents a field whose value * is unavailable (getattr) or which is not to be changed (setattr). */ struct vattr { __enum_uint8(vtype) va_type; /* vnode type (for create) */ u_short va_mode; /* files access mode and type */ uint16_t va_bsdflags; /* same as st_bsdflags from stat(2) */ uid_t va_uid; /* owner user id */ gid_t va_gid; /* owner group id */ nlink_t va_nlink; /* number of references to file */ dev_t va_fsid; /* filesystem id */ ino_t va_fileid; /* file id */ u_quad_t va_size; /* file size in bytes */ long va_blocksize; /* blocksize preferred for i/o */ struct timespec va_atime; /* time of last access */ struct timespec va_mtime; /* time of last modification */ struct timespec va_ctime; /* time file changed */ struct timespec va_birthtime; /* time file created */ u_long va_gen; /* generation number of file */ u_long va_flags; /* flags defined for file */ dev_t va_rdev; /* device the special file represents */ u_quad_t va_bytes; /* bytes of disk space held by file */ u_quad_t va_filerev; /* file modification number */ u_int va_vaflags; /* operations flags, see below */ long va_spare; /* remain quad aligned */ }; #define VATTR_ISDEV(vap) VTYPE_ISDEV((vap)->va_type) /* * Flags for va_vaflags. */ #define VA_UTIMES_NULL 0x01 /* utimes argument was NULL */ #define VA_EXCLUSIVE 0x02 /* exclusive create request */ #define VA_SYNC 0x04 /* O_SYNC truncation */ /* * Flags for ioflag. (high 16 bits used to ask for read-ahead and * help with write clustering) * NB: IO_NDELAY and IO_DIRECT are linked to fcntl.h */ #define IO_UNIT 0x0001 /* do I/O as atomic unit */ #define IO_APPEND 0x0002 /* append write to end */ #define IO_NDELAY 0x0004 /* FNDELAY flag set in file table */ #define IO_NODELOCKED 0x0008 /* underlying node already locked */ #define IO_ASYNC 0x0010 /* bawrite rather then bdwrite */ #define IO_VMIO 0x0020 /* data already in VMIO space */ #define IO_INVAL 0x0040 /* invalidate after I/O */ #define IO_SYNC 0x0080 /* do I/O synchronously */ #define IO_DIRECT 0x0100 /* attempt to bypass buffer cache */ #define IO_NOREUSE 0x0200 /* VMIO data won't be reused */ #define IO_EXT 0x0400 /* operate on external attributes */ #define IO_NORMAL 0x0800 /* operate on regular data */ #define IO_NOMACCHECK 0x1000 /* MAC checks unnecessary */ #define IO_BUFLOCKED 0x2000 /* ffs flag; indir buf is locked */ #define IO_RANGELOCKED 0x4000 /* range locked */ #define IO_DATASYNC 0x8000 /* do only data I/O synchronously */ #define IO_SEQMAX 0x7F /* seq heuristic max value */ #define IO_SEQSHIFT 16 /* seq heuristic in upper 16 bits */ /* * Flags for accmode_t. */ #define VEXEC 000000000100 /* execute/search permission */ #define VWRITE 000000000200 /* write permission */ #define VREAD 000000000400 /* read permission */ #define VADMIN 000000010000 /* being the file owner */ #define VAPPEND 000000040000 /* permission to write/append */ /* * VEXPLICIT_DENY makes VOP_ACCESSX(9) return EPERM or EACCES only * if permission was denied explicitly, by a "deny" rule in NFSv4 ACL, * and 0 otherwise. This never happens with ordinary unix access rights * or POSIX.1e ACLs. Obviously, VEXPLICIT_DENY must be OR-ed with * some other V* constant. */ #define VEXPLICIT_DENY 000000100000 #define VREAD_NAMED_ATTRS 000000200000 /* not used */ #define VWRITE_NAMED_ATTRS 000000400000 /* not used */ #define VDELETE_CHILD 000001000000 #define VREAD_ATTRIBUTES 000002000000 /* permission to stat(2) */ #define VWRITE_ATTRIBUTES 000004000000 /* change {m,c,a}time */ #define VDELETE 000010000000 #define VREAD_ACL 000020000000 /* read ACL and file mode */ #define VWRITE_ACL 000040000000 /* change ACL and/or file mode */ #define VWRITE_OWNER 000100000000 /* change file owner */ #define VSYNCHRONIZE 000200000000 /* not used */ #define VCREAT 000400000000 /* creating new file */ #define VVERIFY 001000000000 /* verification required */ /* * Permissions that were traditionally granted only to the file owner. */ #define VADMIN_PERMS (VADMIN | VWRITE_ATTRIBUTES | VWRITE_ACL | \ VWRITE_OWNER) /* * Permissions that were traditionally granted to everyone. */ #define VSTAT_PERMS (VREAD_ATTRIBUTES | VREAD_ACL) /* * Permissions that allow to change the state of the file in any way. */ #define VMODIFY_PERMS (VWRITE | VAPPEND | VADMIN_PERMS | VDELETE_CHILD | \ VDELETE) /* * Token indicating no attribute value yet assigned. */ #define VNOVAL (-1) /* * LK_TIMELOCK timeout for vnode locks (used mainly by the pageout daemon) */ #define VLKTIMEOUT (hz / 20 + 1) #ifdef _KERNEL #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_VNODE); #endif extern u_int ncsizefactor; extern const u_int io_hold_cnt; /* * Convert between vnode types and inode formats (since POSIX.1 * defines mode word of stat structure in terms of inode formats). */ extern __enum_uint8(vtype) iftovt_tab[]; extern int vttoif_tab[]; #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12]) #define VTTOIF(indx) (vttoif_tab[(int)(indx)]) #define MAKEIMODE(indx, mode) (int)(VTTOIF(indx) | (mode)) /* * Flags to various vnode functions. */ #define SKIPSYSTEM 0x0001 /* vflush: skip vnodes marked VSYSTEM */ #define FORCECLOSE 0x0002 /* vflush: force file closure */ #define WRITECLOSE 0x0004 /* vflush: only close writable files */ #define EARLYFLUSH 0x0008 /* vflush: early call for ffs_flushfiles */ #define V_SAVE 0x0001 /* vinvalbuf: sync file first */ #define V_ALT 0x0002 /* vinvalbuf: invalidate only alternate bufs */ #define V_NORMAL 0x0004 /* vinvalbuf: invalidate only regular bufs */ #define V_CLEANONLY 0x0008 /* vinvalbuf: invalidate only clean bufs */ #define V_VMIO 0x0010 /* vinvalbuf: called during pageout */ #define V_ALLOWCLEAN 0x0020 /* vinvalbuf: allow clean buffers after flush */ #define REVOKEALL 0x0001 /* vop_revoke: revoke all aliases */ #define V_WAIT 0x0001 /* vn_start_write: sleep for suspend */ #define V_NOWAIT 0x0002 /* vn_start_write: don't sleep for suspend */ #define V_XSLEEP 0x0004 /* vn_start_write: just return after sleep */ #define V_PCATCH 0x0008 /* vn_start_write: make the sleep interruptible */ #define V_VALID_FLAGS (V_WAIT | V_NOWAIT | V_XSLEEP | V_PCATCH) #define VR_START_WRITE 0x0001 /* vfs_write_resume: start write atomically */ #define VR_NO_SUSPCLR 0x0002 /* vfs_write_resume: do not clear suspension */ #define VS_SKIP_UNMOUNT 0x0001 /* vfs_write_suspend: fail if the filesystem is being unmounted */ -#define VREF(vp) vref(vp) - #ifdef DIAGNOSTIC #define VATTR_NULL(vap) vattr_null(vap) #else #define VATTR_NULL(vap) (*(vap) = va_null) /* initialize a vattr */ #endif /* DIAGNOSTIC */ /* * Global vnode data. */ extern struct vnode *rootvnode; /* root (i.e. "/") vnode */ extern struct mount *rootdevmp; /* "/dev" mount */ extern u_long desiredvnodes; /* number of vnodes desired */ extern struct uma_zone *namei_zone; extern struct vattr va_null; /* predefined null vattr structure */ extern u_int vn_lock_pair_pause_max; #define VI_LOCK(vp) mtx_lock(&(vp)->v_interlock) #define VI_LOCK_FLAGS(vp, flags) mtx_lock_flags(&(vp)->v_interlock, (flags)) #define VI_TRYLOCK(vp) mtx_trylock(&(vp)->v_interlock) #define VI_UNLOCK(vp) mtx_unlock(&(vp)->v_interlock) #define VI_MTX(vp) (&(vp)->v_interlock) #define VN_LOCK_AREC(vp) lockallowrecurse((vp)->v_vnlock) #define VN_LOCK_ASHARE(vp) lockallowshare((vp)->v_vnlock) #define VN_LOCK_DSHARE(vp) lockdisableshare((vp)->v_vnlock) #endif /* _KERNEL */ /* * Mods for extensibility. */ /* * Flags for vdesc_flags: */ #define VDESC_MAX_VPS 16 /* Low order 16 flag bits are reserved for willrele flags for vp arguments. */ #define VDESC_VP0_WILLRELE 0x0001 #define VDESC_VP1_WILLRELE 0x0002 #define VDESC_VP2_WILLRELE 0x0004 #define VDESC_VP3_WILLRELE 0x0008 /* * A generic structure. * This can be used by bypass routines to identify generic arguments. */ struct vop_generic_args { struct vnodeop_desc *a_desc; /* other random data follows, presumably */ }; typedef int vop_bypass_t(struct vop_generic_args *); /* * VDESC_NO_OFFSET is used to identify the end of the offset list * and in places where no such field exists. */ #define VDESC_NO_OFFSET -1 /* * This structure describes the vnode operation taking place. */ struct vnodeop_desc { char *vdesc_name; /* a readable name for debugging */ int vdesc_flags; /* VDESC_* flags */ int vdesc_vop_offset; vop_bypass_t *vdesc_call; /* Function to call */ /* * These ops are used by bypass routines to map and locate arguments. * Creds and procs are not needed in bypass routines, but sometimes * they are useful to (for example) transport layers. * Nameidata is useful because it has a cred in it. */ int *vdesc_vp_offsets; /* list ended by VDESC_NO_OFFSET */ int vdesc_vpp_offset; /* return vpp location */ int vdesc_cred_offset; /* cred location, if any */ int vdesc_thread_offset; /* thread location, if any */ int vdesc_componentname_offset; /* if any */ }; #ifdef _KERNEL /* * A list of all the operation descs. */ extern struct vnodeop_desc *vnodeop_descs[]; #define VOPARG_OFFSETOF(s_type, field) __offsetof(s_type, field) #define VOPARG_OFFSETTO(s_type, s_offset, struct_p) \ ((s_type)(((char*)(struct_p)) + (s_offset))) #ifdef INVARIANTS /* * Support code to aid in debugging VFS locking problems. Not totally * reliable since if the thread sleeps between changing the lock * state and checking it with the assert, some other thread could * change the state. They are good enough for debugging a single * filesystem using a single-threaded test. Note that the unreliability is * limited to false negatives; efforts were made to ensure that false * positives cannot occur. */ void assert_vi_locked(struct vnode *vp, const char *str); void assert_vi_unlocked(struct vnode *vp, const char *str); void assert_vop_elocked(struct vnode *vp, const char *str); void assert_vop_locked(struct vnode *vp, const char *str); void assert_vop_unlocked(struct vnode *vp, const char *str); #define ASSERT_VI_LOCKED(vp, str) assert_vi_locked((vp), (str)) #define ASSERT_VI_UNLOCKED(vp, str) assert_vi_unlocked((vp), (str)) #define ASSERT_VOP_ELOCKED(vp, str) assert_vop_elocked((vp), (str)) #define ASSERT_VOP_LOCKED(vp, str) assert_vop_locked((vp), (str)) #define ASSERT_VOP_UNLOCKED(vp, str) assert_vop_unlocked((vp), (str)) #define ASSERT_VOP_IN_SEQC(vp) do { \ struct vnode *_vp = (vp); \ \ VNPASS(seqc_in_modify(_vp->v_seqc), _vp); \ } while (0) #define ASSERT_VOP_NOT_IN_SEQC(vp) do { \ struct vnode *_vp = (vp); \ \ VNPASS(!seqc_in_modify(_vp->v_seqc), _vp); \ } while (0) #else /* !INVARIANTS */ #define ASSERT_VI_LOCKED(vp, str) ((void)0) #define ASSERT_VI_UNLOCKED(vp, str) ((void)0) #define ASSERT_VOP_ELOCKED(vp, str) ((void)0) #define ASSERT_VOP_LOCKED(vp, str) ((void)0) #define ASSERT_VOP_UNLOCKED(vp, str) ((void)0) #define ASSERT_VOP_IN_SEQC(vp) ((void)0) #define ASSERT_VOP_NOT_IN_SEQC(vp) ((void)0) #endif /* INVARIANTS */ #define DOINGASYNC(vp) \ (((vp)->v_mount->mnt_kern_flag & MNTK_ASYNC) != 0 && \ ((curthread->td_pflags & TDP_SYNCIO) == 0)) /* * VMIO support inline */ extern int vmiodirenable; static __inline int vn_canvmio(struct vnode *vp) { if (vp && (vp->v_type == VREG || (vmiodirenable && vp->v_type == VDIR))) return(TRUE); return(FALSE); } /* * Finally, include the default set of vnode operations. */ typedef void vop_getpages_iodone_t(void *, vm_page_t *, int, int); #include "vnode_if.h" /* vn_open_flags */ #define VN_OPEN_NOAUDIT 0x00000001 #define VN_OPEN_NOCAPCHECK 0x00000002 #define VN_OPEN_NAMECACHE 0x00000004 #define VN_OPEN_INVFS 0x00000008 #define VN_OPEN_WANTIOCTLCAPS 0x00000010 /* copy_file_range kernel flags */ #define COPY_FILE_RANGE_KFLAGS 0xff000000 #define COPY_FILE_RANGE_TIMEO1SEC 0x01000000 /* Return after 1sec. */ /* * Public vnode manipulation functions. */ struct componentname; struct file; struct mount; struct nameidata; struct ostat; struct freebsd11_stat; struct thread; struct proc; struct stat; struct nstat; struct ucred; struct uio; struct vattr; struct vfsops; struct vnode; typedef int (*vn_get_ino_t)(struct mount *, void *, int, struct vnode **); int bnoreuselist(struct bufv *bufv, struct bufobj *bo, daddr_t startn, daddr_t endn); /* cache_* may belong in namei.h. */ void cache_changesize(u_long newhashsize); #define VFS_CACHE_DROPOLD 0x1 void cache_enter_time_flags(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, struct timespec *tsp, struct timespec *dtsp, int flags); #define cache_enter(dvp, vp, cnp) \ cache_enter_time(dvp, vp, cnp, NULL, NULL) void cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, struct timespec *tsp, struct timespec *dtsp); int cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct timespec *tsp, int *ticksp); void cache_vnode_init(struct vnode *vp); void cache_purge(struct vnode *vp); void cache_purge_vgone(struct vnode *vp); void cache_purge_negative(struct vnode *vp); void cache_purgevfs(struct mount *mp); char *cache_symlink_alloc(size_t size, int flags); void cache_symlink_free(char *string, size_t size); int cache_symlink_resolve(struct cache_fpl *fpl, const char *string, size_t len); void cache_vop_inotify(struct vnode *vp, int event, uint32_t cookie); void cache_vop_rename(struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp, struct componentname *fcnp, struct componentname *tcnp); void cache_vop_rmdir(struct vnode *dvp, struct vnode *vp); void cache_vop_vector_register(struct vop_vector *); #ifdef INVARIANTS void cache_validate(struct vnode *dvp, struct vnode *vp, struct componentname *cnp); void cache_validate_vop_vector(struct mount *mp, struct vop_vector *vops); void cache_assert_no_entries(struct vnode *vp); #else static inline void cache_validate(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) { } static inline void cache_validate_vop_vector(struct mount *mp, struct vop_vector *vops) { } static inline void cache_assert_no_entries(struct vnode *vp) { } #endif void cache_fast_lookup_enabled_recalc(void); int change_dir(struct vnode *vp, struct thread *td); void cvtstat(struct stat *st, struct ostat *ost); int freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb); int freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost); int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, struct vnode **vpp); void getnewvnode_reserve(void); void getnewvnode_drop_reserve(void); int insmntque(struct vnode *vp, struct mount *mp); int insmntque1(struct vnode *vp, struct mount *mp); u_quad_t init_va_filerev(void); int speedup_syncer(void); int vn_vptocnp(struct vnode **vp, char *buf, size_t *buflen); int vn_getcwd(char *buf, char **retbuf, size_t *buflen); int vn_fullpath(struct vnode *vp, char **retbuf, char **freebuf); int vn_fullpath_global(struct vnode *vp, char **retbuf, char **freebuf); int vn_fullpath_hardlink(struct vnode *vp, struct vnode *dvp, const char *hdrl_name, size_t hrdl_name_length, char **retbuf, char **freebuf, size_t *buflen); struct vnode * vn_dir_dd_ino(struct vnode *vp); int vn_commname(struct vnode *vn, char *buf, u_int buflen); int vn_path_to_global_path(struct thread *td, struct vnode *vp, char *path, u_int pathlen); int vn_path_to_global_path_hardlink(struct thread *td, struct vnode *vp, struct vnode *dvp, char *path, u_int pathlen, const char *leaf_name, size_t leaf_length); int vaccess(__enum_uint8(vtype) type, mode_t file_mode, uid_t file_uid, gid_t file_gid, accmode_t accmode, struct ucred *cred); int vaccess_vexec_smr(mode_t file_mode, uid_t file_uid, gid_t file_gid, struct ucred *cred); int vaccess_acl_nfs4(__enum_uint8(vtype) type, uid_t file_uid, gid_t file_gid, struct acl *aclp, accmode_t accmode, struct ucred *cred); int vaccess_acl_posix1e(__enum_uint8(vtype) type, uid_t file_uid, gid_t file_gid, struct acl *acl, accmode_t accmode, struct ucred *cred); void vattr_null(struct vattr *vap); void vlazy(struct vnode *); void vdrop(struct vnode *); void vdropl(struct vnode *); int vflush(struct mount *mp, int rootrefs, int flags, struct thread *td); int vget(struct vnode *vp, int flags); enum vgetstate vget_prep_smr(struct vnode *vp); enum vgetstate vget_prep(struct vnode *vp); int vget_finish(struct vnode *vp, int flags, enum vgetstate vs); void vget_finish_ref(struct vnode *vp, enum vgetstate vs); void vget_abort(struct vnode *vp, enum vgetstate vs); void vgone(struct vnode *vp); void vhold(struct vnode *); void vholdnz(struct vnode *); bool vhold_smr(struct vnode *); int vinactive(struct vnode *vp); int vinvalbuf(struct vnode *vp, int save, int slpflag, int slptimeo); int vtruncbuf(struct vnode *vp, off_t length, int blksize); void v_inval_buf_range(struct vnode *vp, daddr_t startlbn, daddr_t endlbn, int blksize); void vunref(struct vnode *); void vn_printf(struct vnode *vp, const char *fmt, ...) __printflike(2,3); int vrecycle(struct vnode *vp); int vrecyclel(struct vnode *vp); int vn_bmap_seekhole_locked(struct vnode *vp, u_long cmd, off_t *off, struct ucred *cred); int vn_bmap_seekhole(struct vnode *vp, u_long cmd, off_t *off, struct ucred *cred); int vn_close(struct vnode *vp, int flags, struct ucred *file_cred, struct thread *td); int vn_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp, off_t *outoffp, size_t *lenp, unsigned int flags, struct ucred *incred, struct ucred *outcred, struct thread *fsize_td); int vn_deallocate(struct vnode *vp, off_t *offset, off_t *length, int flags, int ioflg, struct ucred *active_cred, struct ucred *file_cred); void vn_finished_write(struct mount *mp); void vn_finished_secondary_write(struct mount *mp); int vn_fsync_buf(struct vnode *vp, int waitfor); int vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp, off_t *outoffp, size_t *lenp, unsigned int flags, struct ucred *incred, struct ucred *outcred, struct thread *fsize_td); int vn_need_pageq_flush(struct vnode *vp); bool vn_isdisk_error(struct vnode *vp, int *errp); bool vn_isdisk(struct vnode *vp); int _vn_lock(struct vnode *vp, int flags, const char *file, int line); #define vn_lock(vp, flags) _vn_lock(vp, flags, __FILE__, __LINE__) void vn_lock_pair(struct vnode *vp1, bool vp1_locked, int lkflags1, struct vnode *vp2, bool vp2_locked, int lkflags2); int vn_open(struct nameidata *ndp, int *flagp, int cmode, struct file *fp); int vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags, struct ucred *cred, struct file *fp); int vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred, struct thread *td, struct file *fp); void vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end); void vn_pages_remove_valid(struct vnode *vp, vm_pindex_t start, vm_pindex_t end); int vn_pollrecord(struct vnode *vp, struct thread *p, int events); int vn_rdwr(enum uio_rw rw, struct vnode *vp, void *base, int len, off_t offset, enum uio_seg segflg, int ioflg, struct ucred *active_cred, struct ucred *file_cred, ssize_t *aresid, struct thread *td); int vn_rdwr_inchunks(enum uio_rw rw, struct vnode *vp, void *base, size_t len, off_t offset, enum uio_seg segflg, int ioflg, struct ucred *active_cred, struct ucred *file_cred, size_t *aresid, struct thread *td); int vn_read_from_obj(struct vnode *vp, struct uio *uio); int vn_rlimit_fsize(const struct vnode *vp, const struct uio *uio, struct thread *td); int vn_rlimit_fsizex(const struct vnode *vp, struct uio *uio, off_t maxfsz, ssize_t *resid_adj, struct thread *td); void vn_rlimit_fsizex_res(struct uio *uio, ssize_t resid_adj); int vn_rlimit_trunc(u_quad_t size, struct thread *td); int vn_start_write(struct vnode *vp, struct mount **mpp, int flags); int vn_start_secondary_write(struct vnode *vp, struct mount **mpp, int flags); int vn_truncate_locked(struct vnode *vp, off_t length, bool sync, struct ucred *cred); int vn_writechk(struct vnode *vp); int vn_extattr_get(struct vnode *vp, int ioflg, int attrnamespace, const char *attrname, int *buflen, char *buf, struct thread *td); int vn_extattr_set(struct vnode *vp, int ioflg, int attrnamespace, const char *attrname, int buflen, char *buf, struct thread *td); int vn_extattr_rm(struct vnode *vp, int ioflg, int attrnamespace, const char *attrname, struct thread *td); int vn_vget_ino(struct vnode *vp, ino_t ino, int lkflags, struct vnode **rvp); int vn_vget_ino_gen(struct vnode *vp, vn_get_ino_t alloc, void *alloc_arg, int lkflags, struct vnode **rvp); int vn_utimes_perm(struct vnode *vp, struct vattr *vap, struct ucred *cred, struct thread *td); int vn_cmp(struct file *, struct file *, struct thread *td); int vn_io_fault_uiomove(char *data, int xfersize, struct uio *uio); int vn_io_fault_pgmove(vm_page_t ma[], vm_offset_t offset, int xfersize, struct uio *uio); void vn_seqc_write_begin_locked(struct vnode *vp); void vn_seqc_write_begin(struct vnode *vp); void vn_seqc_write_end_locked(struct vnode *vp); void vn_seqc_write_end(struct vnode *vp); #define vn_seqc_read_any(vp) seqc_read_any(&(vp)->v_seqc) #define vn_seqc_read_notmodify(vp) seqc_read_notmodify(&(vp)->v_seqc) #define vn_seqc_consistent(vp, seq) seqc_consistent(&(vp)->v_seqc, seq) #define vn_rangelock_unlock(vp, cookie) \ rangelock_unlock(&(vp)->v_rl, (cookie)) #define vn_rangelock_rlock(vp, start, end) \ rangelock_rlock(&(vp)->v_rl, (start), (end)) #define vn_rangelock_tryrlock(vp, start, end) \ rangelock_tryrlock(&(vp)->v_rl, (start), (end)) #define vn_rangelock_wlock(vp, start, end) \ rangelock_wlock(&(vp)->v_rl, (start), (end)) #define vn_rangelock_trywlock(vp, start, end) \ rangelock_trywlock(&(vp)->v_rl, (start), (end)) #define vn_irflag_read(vp) atomic_load_short(&(vp)->v_irflag) void vn_irflag_set_locked(struct vnode *vp, short toset); void vn_irflag_set(struct vnode *vp, short toset); void vn_irflag_set_cond_locked(struct vnode *vp, short toset); void vn_irflag_set_cond(struct vnode *vp, short toset); void vn_irflag_unset_locked(struct vnode *vp, short tounset); void vn_irflag_unset(struct vnode *vp, short tounset); int vfs_cache_lookup(struct vop_lookup_args *ap); int vfs_cache_root(struct mount *mp, int flags, struct vnode **vpp); void vfs_timestamp(struct timespec *); void vfs_write_resume(struct mount *mp, int flags); int vfs_write_suspend(struct mount *mp, int flags); int vfs_write_suspend_umnt(struct mount *mp); struct vnode *vnlru_alloc_marker(void); void vnlru_free_marker(struct vnode *); void vnlru_free_vfsops(int, struct vfsops *, struct vnode *); int vop_stdbmap(struct vop_bmap_args *); int vop_stdfdatasync_buf(struct vop_fdatasync_args *); int vop_stdfsync(struct vop_fsync_args *); int vop_stdgetwritemount(struct vop_getwritemount_args *); int vop_stdgetpages(struct vop_getpages_args *); int vop_stdinactive(struct vop_inactive_args *); int vop_stdneed_inactive(struct vop_need_inactive_args *); int vop_stdinotify(struct vop_inotify_args *); int vop_stdinotify_add_watch(struct vop_inotify_add_watch_args *); int vop_stdioctl(struct vop_ioctl_args *); int vop_stdkqfilter(struct vop_kqfilter_args *); int vop_stdlock(struct vop_lock1_args *); int vop_stdunlock(struct vop_unlock_args *); int vop_stdislocked(struct vop_islocked_args *); int vop_lock(struct vop_lock1_args *); int vop_unlock(struct vop_unlock_args *); int vop_islocked(struct vop_islocked_args *); int vop_stdputpages(struct vop_putpages_args *); int vop_nopoll(struct vop_poll_args *); int vop_stdaccess(struct vop_access_args *ap); int vop_stdaccessx(struct vop_accessx_args *ap); int vop_stdadvise(struct vop_advise_args *ap); int vop_stdadvlock(struct vop_advlock_args *ap); int vop_stdadvlockasync(struct vop_advlockasync_args *ap); int vop_stdadvlockpurge(struct vop_advlockpurge_args *ap); int vop_stdallocate(struct vop_allocate_args *ap); int vop_stddeallocate(struct vop_deallocate_args *ap); int vop_stdset_text(struct vop_set_text_args *ap); int vop_stdpathconf(struct vop_pathconf_args *); int vop_stdpoll(struct vop_poll_args *); int vop_stdvptocnp(struct vop_vptocnp_args *ap); int vop_stdvptofh(struct vop_vptofh_args *ap); int vop_stdunp_bind(struct vop_unp_bind_args *ap); int vop_stdunp_connect(struct vop_unp_connect_args *ap); int vop_stdunp_detach(struct vop_unp_detach_args *ap); int vop_stdadd_writecount_nomsync(struct vop_add_writecount_args *ap); int vop_eopnotsupp(struct vop_generic_args *ap); int vop_ebadf(struct vop_generic_args *ap); int vop_einval(struct vop_generic_args *ap); int vop_enoent(struct vop_generic_args *ap); int vop_enotty(struct vop_generic_args *ap); int vop_eagain(struct vop_generic_args *ap); int vop_null(struct vop_generic_args *ap); int vop_panic(struct vop_generic_args *ap); int dead_poll(struct vop_poll_args *ap); int dead_read(struct vop_read_args *ap); int dead_write(struct vop_write_args *ap); /* These are called from within the actual VOPS. */ void vop_allocate_post(void *a, int rc); void vop_copy_file_range_post(void *ap, int rc); void vop_close_post(void *a, int rc); void vop_create_pre(void *a); void vop_create_post(void *a, int rc); void vop_deallocate_post(void *a, int rc); void vop_whiteout_pre(void *a); void vop_whiteout_post(void *a, int rc); void vop_deleteextattr_pre(void *a); void vop_deleteextattr_post(void *a, int rc); void vop_link_pre(void *a); void vop_link_post(void *a, int rc); void vop_lookup_post(void *a, int rc); void vop_lookup_pre(void *a); void vop_mkdir_pre(void *a); void vop_mkdir_post(void *a, int rc); void vop_mknod_pre(void *a); void vop_mknod_post(void *a, int rc); void vop_open_post(void *a, int rc); void vop_read_post(void *a, int rc); void vop_read_pgcache_post(void *ap, int rc); void vop_reclaim_post(void *a, int rc); void vop_remove_pre(void *a); void vop_remove_post(void *a, int rc); void vop_rename_post(void *a, int rc); void vop_rename_pre(void *a); void vop_rmdir_pre(void *a); void vop_rmdir_post(void *a, int rc); void vop_setattr_pre(void *a); void vop_setattr_post(void *a, int rc); void vop_setacl_pre(void *a); void vop_setacl_post(void *a, int rc); void vop_setextattr_pre(void *a); void vop_setextattr_post(void *a, int rc); void vop_symlink_pre(void *a); void vop_symlink_post(void *a, int rc); int vop_sigdefer(struct vop_vector *vop, struct vop_generic_args *a); #ifdef INVARIANTS void vop_fdatasync_debugpre(void *a); void vop_fdatasync_debugpost(void *a, int rc); void vop_fplookup_vexec_debugpre(void *a); void vop_fplookup_vexec_debugpost(void *a, int rc); void vop_fplookup_symlink_debugpre(void *a); void vop_fplookup_symlink_debugpost(void *a, int rc); void vop_fsync_debugpre(void *a); void vop_fsync_debugpost(void *a, int rc); void vop_strategy_debugpre(void *a); void vop_lock_debugpre(void *a); void vop_lock_debugpost(void *a, int rc); void vop_unlock_debugpre(void *a); void vop_need_inactive_debugpre(void *a); void vop_need_inactive_debugpost(void *a, int rc); void vop_mkdir_debugpost(void *a, int rc); #else #define vop_fdatasync_debugpre(x) do { } while (0) #define vop_fdatasync_debugpost(x, y) do { } while (0) #define vop_fplookup_vexec_debugpre(x) do { } while (0) #define vop_fplookup_vexec_debugpost(x, y) do { } while (0) #define vop_fplookup_symlink_debugpre(x) do { } while (0) #define vop_fplookup_symlink_debugpost(x, y) do { } while (0) #define vop_fsync_debugpre(x) do { } while (0) #define vop_fsync_debugpost(x, y) do { } while (0) #define vop_strategy_debugpre(x) do { } while (0) #define vop_lock_debugpre(x) do { } while (0) #define vop_lock_debugpost(x, y) do { } while (0) #define vop_unlock_debugpre(x) do { } while (0) #define vop_need_inactive_debugpre(x) do { } while (0) #define vop_need_inactive_debugpost(x, y) do { } while (0) #define vop_mkdir_debugpost(x, y) do { } while (0) #endif void vop_rename_fail(struct vop_rename_args *ap); #define vop_stat_helper_pre(ap) ({ \ struct vop_stat_args *_ap = (ap); \ int _error; \ AUDIT_ARG_VNODE1(ap->a_vp); \ _error = mac_vnode_check_stat(_ap->a_active_cred, _ap->a_file_cred, _ap->a_vp);\ if (__predict_true(_error == 0)) { \ ap->a_sb->st_padding1 = 0; \ bzero(_ap->a_sb->st_spare, sizeof(_ap->a_sb->st_spare)); \ ap->a_sb->st_filerev = 0; \ ap->a_sb->st_bsdflags = 0; \ } \ _error; \ }) #define vop_stat_helper_post(ap, error) ({ \ struct vop_stat_args *_ap = (ap); \ int _error = (error); \ if (priv_check_cred_vfs_generation(_ap->a_active_cred)) \ _ap->a_sb->st_gen = 0; \ _error; \ }) #ifdef INVARIANTS #define vop_readdir_pre_assert(ap) \ ssize_t nresid, oresid; \ \ oresid = (ap)->a_uio->uio_resid; #define vop_readdir_post_assert(ap, ret) \ nresid = (ap)->a_uio->uio_resid; \ if ((ret) == 0 && (ap)->a_eofflag != NULL) { \ VNASSERT(oresid == 0 || nresid != oresid || \ *(ap)->a_eofflag == 1, \ (ap)->a_vp, ("VOP_READDIR: eofflag not set")); \ } #else #define vop_readdir_pre_assert(ap) #define vop_readdir_post_assert(ap, ret) #endif #define vop_readdir_pre(ap) do { \ vop_readdir_pre_assert(ap) #define vop_readdir_post(ap, ret) \ vop_readdir_post_assert(ap, ret); \ if ((ret) == 0) { \ VFS_KNOTE_LOCKED((ap)->a_vp, NOTE_READ); \ INOTIFY((ap)->a_vp, IN_ACCESS); \ } \ } while (0) #define vop_write_pre(ap) \ struct vattr va; \ int error; \ off_t osize, ooffset, noffset; \ \ osize = ooffset = noffset = 0; \ if (!VN_KNLIST_EMPTY((ap)->a_vp)) { \ error = VOP_GETATTR((ap)->a_vp, &va, (ap)->a_cred); \ if (error) \ return (error); \ ooffset = (ap)->a_uio->uio_offset; \ osize = (off_t)va.va_size; \ } #define vop_write_post(ap, ret) \ noffset = (ap)->a_uio->uio_offset; \ if (noffset > ooffset) { \ if (!VN_KNLIST_EMPTY((ap)->a_vp)) { \ VFS_KNOTE_LOCKED((ap)->a_vp, NOTE_WRITE | \ (noffset > osize ? NOTE_EXTEND : 0)); \ } \ INOTIFY((ap)->a_vp, IN_MODIFY); \ } #define VOP_LOCK(vp, flags) VOP_LOCK1(vp, flags, __FILE__, __LINE__) #ifdef INVARIANTS #define VOP_ADD_WRITECOUNT_CHECKED(vp, cnt) \ do { \ int error_; \ \ error_ = VOP_ADD_WRITECOUNT((vp), (cnt)); \ VNASSERT(error_ == 0, (vp), ("VOP_ADD_WRITECOUNT returned %d", \ error_)); \ } while (0) #define VOP_SET_TEXT_CHECKED(vp) \ do { \ int error_; \ \ error_ = VOP_SET_TEXT((vp)); \ VNASSERT(error_ == 0, (vp), ("VOP_SET_TEXT returned %d", \ error_)); \ } while (0) #define VOP_UNSET_TEXT_CHECKED(vp) \ do { \ int error_; \ \ error_ = VOP_UNSET_TEXT((vp)); \ VNASSERT(error_ == 0, (vp), ("VOP_UNSET_TEXT returned %d", \ error_)); \ } while (0) #else #define VOP_ADD_WRITECOUNT_CHECKED(vp, cnt) VOP_ADD_WRITECOUNT((vp), (cnt)) #define VOP_SET_TEXT_CHECKED(vp) VOP_SET_TEXT((vp)) #define VOP_UNSET_TEXT_CHECKED(vp) VOP_UNSET_TEXT((vp)) #endif #define VN_IS_DOOMED(vp) __predict_false((vn_irflag_read(vp) & VIRF_DOOMED) != 0) void vput(struct vnode *vp); void vrele(struct vnode *vp); void vref(struct vnode *vp); void vrefact(struct vnode *vp); void v_addpollinfo(struct vnode *vp); static __inline int vrefcnt(struct vnode *vp) { return (vp->v_usecount); } #define vholdl(vp) do { \ ASSERT_VI_LOCKED(vp, __func__); \ vhold(vp); \ } while (0) #define vrefl(vp) do { \ ASSERT_VI_LOCKED(vp, __func__); \ vref(vp); \ } while (0) /* * The caller doesn't know the file size and vnode_create_vobject() should * determine the size on its own. */ #define VNODE_NO_SIZE ((off_t)-1) int vnode_create_vobject(struct vnode *vp, off_t size, struct thread *td); int vnode_create_disk_vobject(struct vnode *vp, off_t size, struct thread *td); void vnode_destroy_vobject(struct vnode *vp); extern struct vop_vector fifo_specops; extern struct vop_vector dead_vnodeops; extern struct vop_vector default_vnodeops; #define VOP_PANIC ((void*)(uintptr_t)vop_panic) #define VOP_NULL ((void*)(uintptr_t)vop_null) #define VOP_EBADF ((void*)(uintptr_t)vop_ebadf) #define VOP_ENOTTY ((void*)(uintptr_t)vop_enotty) #define VOP_EINVAL ((void*)(uintptr_t)vop_einval) #define VOP_ENOENT ((void*)(uintptr_t)vop_enoent) #define VOP_EOPNOTSUPP ((void*)(uintptr_t)vop_eopnotsupp) #define VOP_EAGAIN ((void*)(uintptr_t)vop_eagain) /* fifo_vnops.c */ int fifo_printinfo(struct vnode *); /* vfs_hash.c */ typedef int vfs_hash_cmp_t(struct vnode *vp, void *arg); void vfs_hash_changesize(u_long newhashsize); int vfs_hash_get(const struct mount *mp, u_int hash, int flags, struct thread *td, struct vnode **vpp, vfs_hash_cmp_t *fn, void *arg); u_int vfs_hash_index(struct vnode *vp); int vfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, struct vnode **vpp, vfs_hash_cmp_t *fn, void *arg); void vfs_hash_ref(const struct mount *mp, u_int hash, struct thread *td, struct vnode **vpp, vfs_hash_cmp_t *fn, void *arg); void vfs_hash_rehash(struct vnode *vp, u_int hash); void vfs_hash_remove(struct vnode *vp); int vfs_kqfilter(struct vop_kqfilter_args *); struct dirent; int vn_dir_next_dirent(struct vnode *vp, struct thread *td, char *dirbuf, size_t dirbuflen, struct dirent **dpp, size_t *len, off_t *off, int *eofflag); int vn_dir_check_empty(struct vnode *vp); int vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off); int vfs_unixify_accmode(accmode_t *accmode); void vfs_unp_reclaim(struct vnode *vp); int setfmode(struct thread *td, struct ucred *cred, struct vnode *vp, int mode); int setfown(struct thread *td, struct ucred *cred, struct vnode *vp, uid_t uid, gid_t gid); int vn_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, struct thread *td); int vn_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, struct thread *td); int vn_getsize_locked(struct vnode *vp, off_t *size, struct ucred *active_cred); int vn_getsize(struct vnode *vp, off_t *size, struct ucred *active_cred); void vn_fsid(struct vnode *vp, struct vattr *va); int vn_dir_check_exec(struct vnode *vp, struct componentname *cnp); int vn_lktype_write(struct mount *mp, struct vnode *vp); #ifdef INVARIANTS void vn_set_state_validate(struct vnode *vp, __enum_uint8(vstate) state); #endif static inline void vn_set_state(struct vnode *vp, __enum_uint8(vstate) state) { #ifdef INVARIANTS vn_set_state_validate(vp, state); #endif vp->v_state = state; } static inline __enum_uint8(vstate) vn_get_state(struct vnode *vp) { return (vp->v_state); } #define VOP_UNLOCK_FLAGS(vp, flags) ({ \ struct vnode *_vp = (vp); \ int _flags = (flags); \ int _error; \ \ if ((_flags & ~(LK_INTERLOCK | LK_RELEASE)) != 0) \ panic("%s: unsupported flags %x\n", __func__, flags); \ _error = VOP_UNLOCK(_vp); \ if (_flags & LK_INTERLOCK) \ VI_UNLOCK(_vp); \ _error; \ }) #include #define VFS_VOP_VECTOR_REGISTER(vnodeops) \ SYSINIT(vfs_vector_##vnodeops##_f, SI_SUB_VFS, SI_ORDER_ANY, \ vfs_vector_op_register, &vnodeops) #define VFS_SMR_DECLARE \ extern smr_t vfs_smr #define VFS_SMR() vfs_smr #define vfs_smr_enter() smr_enter(VFS_SMR()) #define vfs_smr_exit() smr_exit(VFS_SMR()) #define vfs_smr_synchronize() smr_synchronize(VFS_SMR()) #define vfs_smr_entered_load(ptr) smr_entered_load((ptr), VFS_SMR()) #define VFS_SMR_ENTERED() SMR_ENTERED(VFS_SMR()) #define VFS_SMR_ASSERT_ENTERED() SMR_ASSERT_ENTERED(VFS_SMR()) #define VFS_SMR_ASSERT_NOT_ENTERED() SMR_ASSERT_NOT_ENTERED(VFS_SMR()) #define VFS_SMR_ZONE_SET(zone) uma_zone_set_smr((zone), VFS_SMR()) #define vn_load_v_data_smr(vp) ({ \ struct vnode *_vp = (vp); \ \ VFS_SMR_ASSERT_ENTERED(); \ atomic_load_consume_ptr(&(_vp)->v_data);\ }) #endif /* _KERNEL */ #endif /* !_SYS_VNODE_H_ */ diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index 9221aa63184d..419ec3de8572 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -1,1568 +1,1568 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 #include "opt_ufs.h" #include "opt_quota.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef UFS_DIRHASH #include #endif #include #include #include #ifdef DIAGNOSTIC static int dirchk = 1; #else static int dirchk = 0; #endif SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); static int ufs_delete_denied(struct vnode *vdp, struct vnode *tdp, struct ucred *cred, struct thread *td) { int error; #ifdef UFS_ACL /* * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt * * 3.16.2.1. ACE4_DELETE vs. ACE4_DELETE_CHILD */ /* * XXX: Is this check required? */ error = VOP_ACCESS(vdp, VEXEC, cred, td); if (error) return (error); error = VOP_ACCESSX(tdp, VDELETE, cred, td); if (error == 0) return (0); error = VOP_ACCESSX(vdp, VDELETE_CHILD, cred, td); if (error == 0) return (0); error = VOP_ACCESSX(vdp, VEXPLICIT_DENY | VDELETE_CHILD, cred, td); if (error) return (error); #endif /* !UFS_ACL */ /* * Standard Unix access control - delete access requires VWRITE. */ error = VOP_ACCESS(vdp, VWRITE, cred, td); if (error) return (error); /* * If directory is "sticky", then user must own * the directory, or the file in it, else she * may not delete it (unless she's root). This * implements append-only directories. */ if ((VTOI(vdp)->i_mode & ISVTX) && VOP_ACCESS(vdp, VADMIN, cred, td) && VOP_ACCESS(tdp, VADMIN, cred, td)) return (EPERM); return (0); } /* * Convert a component of a pathname into a pointer to a locked inode. * This is a very central and rather complicated routine. * If the filesystem is not maintained in a strict tree hierarchy, * this can result in a deadlock situation (see comments in code below). * * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending * on whether the name is to be looked up, created, renamed, or deleted. * When CREATE, RENAME, or DELETE is specified, information usable in * creating, renaming, or deleting a directory entry may be calculated. * If flag has LOCKPARENT or'ed into it and the target of the pathname * exists, lookup returns both the target and its parent directory locked. * When creating or renaming and LOCKPARENT is specified, the target may * not be ".". When deleting and LOCKPARENT is specified, the target may * be "."., but the caller must check to ensure it does an vrele and vput * instead of two vputs. * * This routine is actually used as VOP_CACHEDLOOKUP method, and the * filesystem employs the generic vfs_cache_lookup() as VOP_LOOKUP * method. * * vfs_cache_lookup() performs the following for us: * check that it is a directory * check accessibility of directory * check for modification attempts on read-only mounts * if name found in cache * if at end of path and deleting or creating * drop it * else * return name. * return VOP_CACHEDLOOKUP() * * Overall outline of ufs_lookup: * * search for name in directory, to found or notfound * notfound: * if creating, return locked directory, leaving info on available slots * else return error * found: * if at end of path and deleting, return information to allow delete * if at end of path and rewriting (RENAME and LOCKPARENT), lock target * inode and return info to allow rewrite * if not at end, add name to cache; if at end and neither creating * nor deleting, add name to cache */ int ufs_lookup( struct vop_cachedlookup_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; } */ *ap) { return (ufs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL)); } int ufs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp, ino_t *dd_ino) { struct inode *dp; /* inode for directory being searched */ struct buf *bp; /* a buffer of directory entries */ struct direct *ep; /* the current directory entry */ int entryoffsetinblock; /* offset of ep in bp's buffer */ enum {NONE, COMPACT, FOUND} slotstatus; doff_t slotoffset; /* offset of area with free space */ doff_t i_diroff; /* cached i_diroff value. */ doff_t i_offset; /* cached i_offset value. */ int slotsize; /* size of area at slotoffset */ int slotfreespace; /* amount of space free in slot */ int slotneeded; /* size of the entry we're seeking */ int numdirpasses; /* strategy for directory search */ doff_t endsearch; /* offset to end directory search */ doff_t prevoff; /* prev entry dp->i_offset */ struct vnode *pdp; /* saved dp during symlink work */ struct vnode *tdp; /* returned by VFS_VGET */ doff_t enduseful; /* pointer past last used dir slot */ uint64_t bmask; /* block offset mask */ int namlen, error; struct ucred *cred = cnp->cn_cred; int flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; ino_t ino, ino1; int ltype; if (vpp != NULL) *vpp = NULL; dp = VTOI(vdp); if (dp->i_effnlink == 0) return (ENOENT); /* * Create a vm object if vmiodirenable is enabled. * Alternatively we could call vnode_create_vobject * in VFS_VGET but we could end up creating objects * that are never used. */ vnode_create_vobject(vdp, DIP(dp, i_size), curthread); bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; /* * Assert that the directory vnode is locked, and locked * exclusively for the last component lookup for modifying * operations. * * The directory-modifying operations need to save * intermediate state in the inode between namei() call and * actual directory manipulations. See fields in the struct * inode marked as 'used during directory lookup'. We must * ensure that upgrade in namei() does not happen, since * upgrade might need to unlock vdp. If quotas are enabled, * getinoquota() also requires exclusive lock to modify inode. */ ASSERT_VOP_LOCKED(vdp, "ufs_lookup1"); if ((nameiop == CREATE || nameiop == DELETE || nameiop == RENAME) && (flags & (LOCKPARENT | ISLASTCN)) == (LOCKPARENT | ISLASTCN)) ASSERT_VOP_ELOCKED(vdp, "ufs_lookup2"); restart: bp = NULL; slotoffset = -1; /* * We now have a segment name to search for, and a directory to search. * * Suppress search for slots unless creating * file and at end of pathname, in which case * we watch for a place to put the new file in * case it doesn't already exist. */ ino = 0; i_diroff = dp->i_diroff; slotstatus = FOUND; slotfreespace = slotsize = slotneeded = 0; if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) { slotstatus = NONE; slotneeded = DIRECTSIZ(cnp->cn_namelen); } #ifdef UFS_DIRHASH /* * Use dirhash for fast operations on large directories. The logic * to determine whether to hash the directory is contained within * ufsdirhash_build(); a zero return means that it decided to hash * this directory and it successfully built up the hash table. */ if (ufsdirhash_build(dp) == 0) { /* Look for a free slot if needed. */ enduseful = dp->i_size; if (slotstatus != FOUND) { slotoffset = ufsdirhash_findfree(dp, slotneeded, &slotsize); if (slotoffset >= 0) { slotstatus = COMPACT; enduseful = ufsdirhash_enduseful(dp); if (enduseful < 0) enduseful = dp->i_size; } } /* Look up the component. */ numdirpasses = 1; entryoffsetinblock = 0; /* silence compiler warning */ switch (ufsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen, &i_offset, &bp, nameiop == DELETE ? &prevoff : NULL)) { case 0: ep = (struct direct *)((char *)bp->b_data + (i_offset & bmask)); goto foundentry; case ENOENT: i_offset = roundup2(dp->i_size, DIRBLKSIZ); goto notfound; default: /* Something failed; just do a linear search. */ break; } } #endif /* UFS_DIRHASH */ /* * If there is cached information on a previous search of * this directory, pick up where we last left off. * We cache only lookups as these are the most common * and have the greatest payoff. Caching CREATE has little * benefit as it usually must search the entire directory * to determine that the entry does not exist. Caching the * location of the last DELETE or RENAME has not reduced * profiling time and hence has been removed in the interest * of simplicity. */ if (nameiop != LOOKUP || i_diroff == 0 || i_diroff >= dp->i_size) { entryoffsetinblock = 0; i_offset = 0; numdirpasses = 1; } else { i_offset = i_diroff; if ((entryoffsetinblock = i_offset & bmask) && (error = UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp))) return (error); numdirpasses = 2; nchstats.ncs_2passes++; } prevoff = i_offset; endsearch = roundup2(dp->i_size, DIRBLKSIZ); enduseful = 0; searchloop: while (i_offset < endsearch) { /* * If necessary, get the next directory block. */ if ((i_offset & bmask) == 0) { if (bp != NULL) brelse(bp); error = UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp); if (error) return (error); entryoffsetinblock = 0; } /* * If still looking for a slot, and at a DIRBLKSIZE * boundary, have to start looking for free space again. */ if (slotstatus == NONE && (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) { slotoffset = -1; slotfreespace = 0; } /* * Get pointer to next entry. * Full validation checks are slow, so we only check * enough to insure forward progress through the * directory. Complete checks can be run by patching * "dirchk" to be true. */ ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock); if (ep->d_reclen == 0 || ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) { int i; ufs_dirbad(dp, i_offset, "mangled entry"); i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); i_offset += i; entryoffsetinblock += i; continue; } /* * If an appropriate sized slot has not yet been found, * check to see if one is available. Also accumulate space * in the current block so that we can determine if * compaction is viable. */ if (slotstatus != FOUND) { int size = ep->d_reclen; if (ep->d_ino != 0) size -= DIRSIZ(OFSFMT(vdp), ep); if (size > 0) { if (size >= slotneeded) { slotstatus = FOUND; slotoffset = i_offset; slotsize = ep->d_reclen; } else if (slotstatus == NONE) { slotfreespace += size; if (slotoffset == -1) slotoffset = i_offset; if (slotfreespace >= slotneeded) { slotstatus = COMPACT; slotsize = i_offset + ep->d_reclen - slotoffset; } } } } /* * Check for a name match. */ if (ep->d_ino) { # if (BYTE_ORDER == LITTLE_ENDIAN) if (OFSFMT(vdp)) namlen = ep->d_type; else namlen = ep->d_namlen; # else namlen = ep->d_namlen; # endif if (namlen == cnp->cn_namelen && (cnp->cn_nameptr[0] == ep->d_name[0]) && !bcmp(cnp->cn_nameptr, ep->d_name, (unsigned)namlen)) { #ifdef UFS_DIRHASH foundentry: #endif /* * Save directory entry's inode number and * reclen in ndp->ni_ufs area, and release * directory buffer. */ if (!OFSFMT(vdp) && ep->d_type == DT_WHT) { slotstatus = FOUND; slotoffset = i_offset; slotsize = ep->d_reclen; enduseful = dp->i_size; cnp->cn_flags |= ISWHITEOUT; numdirpasses--; goto notfound; } ino = ep->d_ino; goto found; } } prevoff = i_offset; i_offset += ep->d_reclen; entryoffsetinblock += ep->d_reclen; if (ep->d_ino) enduseful = i_offset; } notfound: /* * If we started in the middle of the directory and failed * to find our target, we must check the beginning as well. */ if (numdirpasses == 2) { numdirpasses--; i_offset = 0; endsearch = i_diroff; goto searchloop; } if (bp != NULL) brelse(bp); /* * If creating, and at end of pathname and current * directory has not been removed, then can consider * allowing file to be created. */ if ((nameiop == CREATE || nameiop == RENAME || (nameiop == DELETE && (cnp->cn_flags & DOWHITEOUT) && (cnp->cn_flags & ISWHITEOUT))) && (flags & ISLASTCN) && dp->i_effnlink != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. * * XXX: Fix the comment above. */ if (flags & WILLBEDIR) error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, curthread); else error = VOP_ACCESS(vdp, VWRITE, cred, curthread); if (error) return (error); /* * Return an indication of where the new directory * entry should be put. If we didn't find a slot, * then set dp->i_count to 0 indicating * that the new slot belongs at the end of the * directory. If we found a slot, then the new entry * can be put in the range from dp->i_offset to * dp->i_offset + dp->i_count. */ if (slotstatus == NONE) { SET_I_OFFSET(dp, roundup2(dp->i_size, DIRBLKSIZ)); SET_I_COUNT(dp, 0); enduseful = I_OFFSET(dp); } else if (nameiop == DELETE) { SET_I_OFFSET(dp, slotoffset); if ((I_OFFSET(dp) & (DIRBLKSIZ - 1)) == 0) SET_I_COUNT(dp, 0); else SET_I_COUNT(dp, I_OFFSET(dp) - prevoff); } else { SET_I_OFFSET(dp, slotoffset); SET_I_COUNT(dp, slotsize); if (enduseful < slotoffset + slotsize) enduseful = slotoffset + slotsize; } SET_I_ENDOFF(dp, roundup2(enduseful, DIRBLKSIZ)); /* * We return with the directory locked, so that * the parameters we set up above will still be * valid if we actually decide to do a direnter(). * We return ni_vp == NULL to indicate that the entry * does not currently exist; we leave a pointer to * the (locked) directory inode in ndp->ni_dvp. * * NB - if the directory is unlocked, then this * information cannot be used. */ return (EJUSTRETURN); } /* * Insert name into cache (as non-existent) if appropriate. */ if ((cnp->cn_flags & MAKEENTRY) != 0) cache_enter(vdp, NULL, cnp); return (ENOENT); found: if (dd_ino != NULL) *dd_ino = ino; if (numdirpasses == 2) nchstats.ncs_pass2++; /* * Check that directory length properly reflects presence * of this entry. */ if (i_offset + DIRSIZ(OFSFMT(vdp), ep) > dp->i_size) { ufs_dirbad(dp, i_offset, "i_size too small"); brelse(bp); return (EIO); } brelse(bp); /* * Found component in pathname. * If the final component of path name, save information * in the cache as to where the entry was found. */ if ((flags & ISLASTCN) && nameiop == LOOKUP) dp->i_diroff = rounddown2(i_offset, DIRBLKSIZ); /* * If deleting, and at end of pathname, return * parameters which can be used to remove file. */ if (nameiop == DELETE && (flags & ISLASTCN)) { if (flags & LOCKPARENT) ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); if (VOP_ISLOCKED(vdp) == LK_EXCLUSIVE) { /* * Return pointer to current entry in * dp->i_offset, and distance past previous * entry (if there is a previous entry in this * block) in dp->i_count. * * We shouldn't be setting these in the * WANTPARENT case (first lookup in rename()), but any * lookups that will result in directory changes will * overwrite these. */ SET_I_OFFSET(dp, i_offset); if ((I_OFFSET(dp) & (DIRBLKSIZ - 1)) == 0) SET_I_COUNT(dp, 0); else SET_I_COUNT(dp, I_OFFSET(dp) - prevoff); } if (dd_ino != NULL) return (0); /* * Save directory inode pointer in ndp->ni_dvp for * dirremove(). */ if ((error = VFS_VGET(vdp->v_mount, ino, LK_EXCLUSIVE, &tdp)) != 0) return (error); error = ufs_delete_denied(vdp, tdp, cred, curthread); if (error) { vput(tdp); return (error); } if (dp->i_number == ino) { - VREF(vdp); + vref(vdp); *vpp = vdp; vput(tdp); return (0); } *vpp = tdp; return (0); } /* * If rewriting (RENAME), return the inode and the * information required to rewrite the present directory * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ if (nameiop == RENAME && (flags & ISLASTCN)) { if (flags & WILLBEDIR) error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, curthread); else error = VOP_ACCESS(vdp, VWRITE, cred, curthread); if (error) return (error); /* * Careful about locking second inode. * This can only occur if the target is ".". */ SET_I_OFFSET(dp, i_offset); if (dp->i_number == ino) return (EISDIR); if (dd_ino != NULL) return (0); if ((error = VFS_VGET(vdp->v_mount, ino, LK_EXCLUSIVE, &tdp)) != 0) return (error); error = ufs_delete_denied(vdp, tdp, cred, curthread); if (error) { vput(tdp); return (error); } #ifdef SunOS_doesnt_do_that /* * The only purpose of this check is to return the correct * error. Assume that we want to rename directory "a" * to a file "b", and that we have no ACL_WRITE_DATA on * a containing directory, but we _do_ have ACL_APPEND_DATA. * In that case, the VOP_ACCESS check above will return 0, * and the operation will fail with ENOTDIR instead * of EACCESS. */ if (tdp->v_type == VDIR) error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, curthread); else error = VOP_ACCESS(vdp, VWRITE, cred, curthread); if (error) { vput(tdp); return (error); } #endif *vpp = tdp; return (0); } if (dd_ino != NULL) return (0); /* * Step through the translation in the name. We do not `vput' the * directory because we may need it again if a symbolic link * is relative to the current directory. Instead we save it * unlocked as "pdp". We must get the target inode before unlocking * the directory to insure that the inode will not be removed * before we get it. We prevent deadlock by always fetching * inodes from the root, moving down the directory tree. Thus * when following backward pointers ".." we must unlock the * parent directory before getting the requested directory. * There is a potential race condition here if both the current * and parent directories are removed before the VFS_VGET for the * inode associated with ".." returns. We hope that this occurs * infrequently since we cannot avoid this race condition without * implementing a sophisticated deadlock detection algorithm. * Note also that this simple deadlock detection scheme will not * work if the filesystem has any hard links other than ".." * that point backwards in the directory structure. */ pdp = vdp; if (flags & ISDOTDOT) { error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp); if (error) return (error); /* * Recheck that ".." entry in the vdp directory points * to the inode we looked up before vdp lock was * dropped. */ error = ufs_lookup_ino(pdp, NULL, cnp, &ino1); if (error) { vput(tdp); return (error); } if (ino1 != ino) { vput(tdp); goto restart; } *vpp = tdp; } else if (dp->i_number == ino) { - VREF(vdp); /* we want ourself, ie "." */ + vref(vdp); /* we want ourself, ie "." */ /* * When we lookup "." we still can be asked to lock it * differently. */ ltype = cnp->cn_lkflags & LK_TYPE_MASK; if (ltype != VOP_ISLOCKED(vdp)) { if (ltype == LK_EXCLUSIVE) vn_lock(vdp, LK_UPGRADE | LK_RETRY); else /* if (ltype == LK_SHARED) */ vn_lock(vdp, LK_DOWNGRADE | LK_RETRY); /* * Relock for the "." case may left us with * reclaimed vnode. */ if (VN_IS_DOOMED(vdp)) { vrele(vdp); return (ENOENT); } } *vpp = vdp; } else { error = VFS_VGET(pdp->v_mount, ino, cnp->cn_lkflags, &tdp); if (error == 0 && VTOI(tdp)->i_mode == 0) { vgone(tdp); vput(tdp); error = ENOENT; } if (error) return (error); *vpp = tdp; } /* * Insert name into cache if appropriate. */ if (cnp->cn_flags & MAKEENTRY) cache_enter(vdp, *vpp, cnp); return (0); } void ufs_dirbad(struct inode *ip, doff_t offset, char *how) { (void)printf("%s: bad dir ino %ju at offset %ld: %s\n", ITOV(ip)->v_mount->mnt_stat.f_mntonname, (uintmax_t)ip->i_number, (long)offset, how); } /* * Do consistency checking on a directory entry: * record length must be multiple of 4 * entry must fit in rest of its DIRBLKSIZ block * record must be large enough to contain entry * name is not longer than UFS_MAXNAMLEN * name must be as long as advertised, and null terminated */ int ufs_dirbadentry(struct vnode *dp, struct direct *ep, int entryoffsetinblock) { int i, namlen; # if (BYTE_ORDER == LITTLE_ENDIAN) if (OFSFMT(dp)) namlen = ep->d_type; else namlen = ep->d_namlen; # else namlen = ep->d_namlen; # endif if ((ep->d_reclen & 0x3) != 0 || ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || ep->d_reclen < DIRSIZ(OFSFMT(dp), ep) || namlen > UFS_MAXNAMLEN) { /*return (1); */ printf("First bad\n"); goto bad; } if (ep->d_ino == 0) return (0); for (i = 0; i < namlen; i++) if (ep->d_name[i] == '\0') { /*return (1); */ printf("Second bad\n"); goto bad; } if (ep->d_name[i]) goto bad; return (0); bad: return (1); } /* * Construct a new directory entry after a call to namei, using the * parameters that it left in the componentname argument cnp. The * argument ip is the inode to which the new directory entry will refer. */ void ufs_makedirentry(struct inode *ip, struct componentname *cnp, struct direct *newdirp) { uint64_t namelen; namelen = (unsigned)cnp->cn_namelen; KASSERT(namelen <= UFS_MAXNAMLEN, ("ufs_makedirentry: name too long")); newdirp->d_ino = ip->i_number; newdirp->d_namlen = namelen; /* Zero out after-name padding */ *(uint32_t *)(&newdirp->d_name[namelen & ~(DIR_ROUNDUP - 1)]) = 0; bcopy(cnp->cn_nameptr, newdirp->d_name, namelen); if (!OFSFMT(ITOV(ip))) newdirp->d_type = IFTODT(ip->i_mode); else { newdirp->d_type = 0; # if (BYTE_ORDER == LITTLE_ENDIAN) { uint8_t tmp = newdirp->d_namlen; newdirp->d_namlen = newdirp->d_type; newdirp->d_type = tmp; } # endif } } /* * Write a directory entry after a call to namei, using the parameters * that it left in nameidata. The argument dirp is the new directory * entry contents. Dvp is a pointer to the directory to be written, * which was left locked by namei. Remaining parameters (dp->i_offset, * dp->i_count) indicate how the space for the new entry is to be obtained. * Non-null bp indicates that a directory is being created (for the * soft dependency code). */ int ufs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp, struct componentname *cnp, struct buf *newdirbp) { struct ucred *cr; struct thread *td; int newentrysize; struct inode *dp; struct buf *bp; uint64_t dsize; struct direct *ep, *nep; uint64_t old_isize; int error, ret, blkoff, loc, spacefree, flags, namlen; char *dirbuf; td = curthread; /* XXX */ cr = td->td_ucred; dp = VTOI(dvp); newentrysize = DIRSIZ(OFSFMT(dvp), dirp); if (I_COUNT(dp) == 0) { /* * If dp->i_count is 0, then namei could find no * space in the directory. Here, dp->i_offset will * be on a directory block boundary and we will write the * new entry into a fresh block. */ if (I_OFFSET(dp) & (DIRBLKSIZ - 1)) panic("ufs_direnter: newblk"); flags = BA_CLRBUF; if (!DOINGSOFTDEP(dvp) && !DOINGASYNC(dvp)) flags |= IO_SYNC; #ifdef QUOTA if ((error = getinoquota(dp)) != 0) { if (DOINGSOFTDEP(dvp) && newdirbp != NULL) bdwrite(newdirbp); return (error); } #endif old_isize = dp->i_size; vnode_pager_setsize(dvp, (vm_ooffset_t)I_OFFSET(dp) + DIRBLKSIZ); if ((error = UFS_BALLOC(dvp, (off_t)I_OFFSET(dp), DIRBLKSIZ, cr, flags, &bp)) != 0) { if (DOINGSOFTDEP(dvp) && newdirbp != NULL) bdwrite(newdirbp); vnode_pager_setsize(dvp, (vm_ooffset_t)old_isize); return (error); } dp->i_size = I_OFFSET(dp) + DIRBLKSIZ; DIP_SET(dp, i_size, dp->i_size); SET_I_ENDOFF(dp, dp->i_size); UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_CHANGE | IN_UPDATE); dirp->d_reclen = DIRBLKSIZ; blkoff = I_OFFSET(dp) & (VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1); bcopy((caddr_t)dirp, (caddr_t)bp->b_data + blkoff,newentrysize); #ifdef UFS_DIRHASH if (dp->i_dirhash != NULL) { ufsdirhash_newblk(dp, I_OFFSET(dp)); ufsdirhash_add(dp, dirp, I_OFFSET(dp)); ufsdirhash_checkblock(dp, (char *)bp->b_data + blkoff, I_OFFSET(dp)); } #endif if (DOINGSOFTDEP(dvp)) { /* * Ensure that the entire newly allocated block is a * valid directory so that future growth within the * block does not have to ensure that the block is * written before the inode. */ blkoff += DIRBLKSIZ; while (blkoff < bp->b_bcount) { ((struct direct *) (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ; blkoff += DIRBLKSIZ; } if (softdep_setup_directory_add(bp, dp, I_OFFSET(dp), dirp->d_ino, newdirbp, 1)) UFS_INODE_SET_FLAG(dp, IN_NEEDSYNC); if (newdirbp) bdwrite(newdirbp); bdwrite(bp); return (UFS_UPDATE(dvp, 0)); } if (DOINGASYNC(dvp)) { bdwrite(bp); return (UFS_UPDATE(dvp, 0)); } error = bwrite(bp); ret = UFS_UPDATE(dvp, 1); if (error == 0) return (ret); return (error); } /* * If dp->i_count is non-zero, then namei found space for the new * entry in the range dp->i_offset to dp->i_offset + dp->i_count * in the directory. To use this space, we may have to compact * the entries located there, by copying them together towards the * beginning of the block, leaving the free space in one usable * chunk at the end. */ /* * Increase size of directory if entry eats into new space. * This should never push the size past a new multiple of * DIRBLKSIZE. * * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. */ if (I_OFFSET(dp) + I_COUNT(dp) > dp->i_size) { dp->i_size = I_OFFSET(dp) + I_COUNT(dp); DIP_SET(dp, i_size, dp->i_size); UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_MODIFIED); } /* * Get the block containing the space for the new directory entry. */ error = UFS_BLKATOFF(dvp, (off_t)I_OFFSET(dp), &dirbuf, &bp); if (error) { if (DOINGSOFTDEP(dvp) && newdirbp != NULL) bdwrite(newdirbp); return (error); } /* * Find space for the new entry. In the simple case, the entry at * offset base will have the space. If it does not, then namei * arranged that compacting the region dp->i_offset to * dp->i_offset + dp->i_count would yield the space. */ ep = (struct direct *)dirbuf; dsize = ep->d_ino ? DIRSIZ(OFSFMT(dvp), ep) : 0; spacefree = ep->d_reclen - dsize; for (loc = ep->d_reclen; loc < I_COUNT(dp); ) { nep = (struct direct *)(dirbuf + loc); /* Trim the existing slot (NB: dsize may be zero). */ ep->d_reclen = dsize; ep = (struct direct *)((char *)ep + dsize); /* Read nep->d_reclen now as the bcopy() may clobber it. */ loc += nep->d_reclen; if (nep->d_ino == 0) { /* * A mid-block unused entry. Such entries are * never created by the kernel, but fsck_ffs * can create them (and it doesn't fix them). * * Add up the free space, and initialise the * relocated entry since we don't bcopy it. */ spacefree += nep->d_reclen; ep->d_ino = 0; dsize = 0; continue; } dsize = DIRSIZ(OFSFMT(dvp), nep); spacefree += nep->d_reclen - dsize; #ifdef UFS_DIRHASH if (dp->i_dirhash != NULL) ufsdirhash_move(dp, nep, I_OFFSET(dp) + ((char *)nep - dirbuf), I_OFFSET(dp) + ((char *)ep - dirbuf)); #endif if (DOINGSOFTDEP(dvp)) softdep_change_directoryentry_offset(bp, dp, dirbuf, (caddr_t)nep, (caddr_t)ep, dsize); else bcopy((caddr_t)nep, (caddr_t)ep, dsize); } /* * Here, `ep' points to a directory entry containing `dsize' in-use * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0, * then the entry is completely unused (dsize == 0). The value * of ep->d_reclen is always indeterminate. * * Update the pointer fields in the previous entry (if any), * copy in the new entry, and write out the block. */ # if (BYTE_ORDER == LITTLE_ENDIAN) if (OFSFMT(dvp)) namlen = ep->d_type; else namlen = ep->d_namlen; # else namlen = ep->d_namlen; # endif if (ep->d_ino == 0 || (ep->d_ino == UFS_WINO && namlen == dirp->d_namlen && bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) { if (spacefree + dsize < newentrysize) panic("ufs_direnter: compact1"); dirp->d_reclen = spacefree + dsize; } else { if (spacefree < newentrysize) panic("ufs_direnter: compact2"); dirp->d_reclen = spacefree; ep->d_reclen = dsize; ep = (struct direct *)((char *)ep + dsize); } #ifdef UFS_DIRHASH if (dp->i_dirhash != NULL && (ep->d_ino == 0 || dirp->d_reclen == spacefree)) ufsdirhash_add(dp, dirp, I_OFFSET(dp) + ((char *)ep - dirbuf)); #endif bcopy((caddr_t)dirp, (caddr_t)ep, (uint64_t)newentrysize); #ifdef UFS_DIRHASH if (dp->i_dirhash != NULL) ufsdirhash_checkblock(dp, dirbuf - (I_OFFSET(dp) & (DIRBLKSIZ - 1)), rounddown2(I_OFFSET(dp), DIRBLKSIZ)); #endif if (DOINGSOFTDEP(dvp)) { (void) softdep_setup_directory_add(bp, dp, I_OFFSET(dp) + (caddr_t)ep - dirbuf, dirp->d_ino, newdirbp, 0); if (newdirbp != NULL) bdwrite(newdirbp); bdwrite(bp); } else { if (DOINGASYNC(dvp)) { bdwrite(bp); error = 0; } else { error = bwrite(bp); } } /* * If all went well, and the directory can be shortened, * mark directory inode with the truncation request. */ UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE | (error == 0 && I_ENDOFF(dp) != 0 && I_ENDOFF(dp) < dp->i_size ? IN_ENDOFF : 0)); return (error); } /* * Remove a directory entry after a call to namei, using * the parameters which it left in nameidata. The entry * dp->i_offset contains the offset into the directory of the * entry to be eliminated. The dp->i_count field contains the * size of the previous record in the directory. If this * is 0, the first entry is being deleted, so we need only * zero the inode number to mark the entry as free. If the * entry is not the first in the directory, we must reclaim * the space of the now empty record by adding the record size * to the size of the previous entry. */ int ufs_dirremove(struct vnode *dvp, struct inode *ip, int flags, bool isrmdir) { struct inode *dp; struct direct *ep, *rep; struct buf *bp; off_t offset; int error; dp = VTOI(dvp); /* * Adjust the link count early so softdep can block if necessary. */ if (ip) { ip->i_effnlink--; UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(dvp)) { softdep_setup_unlink(dp, ip); } else { ip->i_nlink--; DIP_SET_NLINK(ip, ip->i_nlink); UFS_INODE_SET_FLAG(ip, IN_CHANGE); } } if (flags & DOWHITEOUT) offset = I_OFFSET(dp); else offset = I_OFFSET(dp) - I_COUNT(dp); if ((error = UFS_BLKATOFF(dvp, offset, (char **)&ep, &bp)) != 0) { if (ip) { ip->i_effnlink++; UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(dvp)) { softdep_change_linkcnt(ip); } else { ip->i_nlink++; DIP_SET_NLINK(ip, ip->i_nlink); UFS_INODE_SET_FLAG(ip, IN_CHANGE); } } return (error); } if (flags & DOWHITEOUT) { /* * Whiteout entry: set d_ino to UFS_WINO. */ ep->d_ino = UFS_WINO; ep->d_type = DT_WHT; goto out; } /* Set 'rep' to the entry being removed. */ if (I_COUNT(dp) == 0) rep = ep; else rep = (struct direct *)((char *)ep + ep->d_reclen); #ifdef UFS_DIRHASH /* * Remove the dirhash entry. This is complicated by the fact * that `ep' is the previous entry when dp->i_count != 0. */ if (dp->i_dirhash != NULL) ufsdirhash_remove(dp, rep, I_OFFSET(dp)); #endif if (ip && rep->d_ino != ip->i_number) panic("ufs_dirremove: ip %ju does not match dirent ino %ju\n", (uintmax_t)ip->i_number, (uintmax_t)rep->d_ino); /* * Zero out the file directory entry metadata to reduce disk * scavenging disclosure. */ bzero(&rep->d_name[0], rep->d_namlen); rep->d_namlen = 0; rep->d_type = 0; rep->d_ino = 0; if (I_COUNT(dp) != 0) { /* * Collapse new free space into previous entry. */ ep->d_reclen += rep->d_reclen; rep->d_reclen = 0; } #ifdef UFS_DIRHASH if (dp->i_dirhash != NULL) ufsdirhash_checkblock(dp, (char *)ep - ((I_OFFSET(dp) - I_COUNT(dp)) & (DIRBLKSIZ - 1)), rounddown2(I_OFFSET(dp), DIRBLKSIZ)); #endif out: error = 0; if (DOINGSOFTDEP(dvp)) { if (ip) softdep_setup_remove(bp, dp, ip, isrmdir); if (softdep_slowdown(dvp)) error = bwrite(bp); else bdwrite(bp); } else { if (flags & DOWHITEOUT) error = bwrite(bp); else if (DOINGASYNC(dvp)) bdwrite(bp); else error = bwrite(bp); } UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE); /* * If the last named reference to a snapshot goes away, * drop its snapshot reference so that it will be reclaimed * when last open reference goes away. */ if (ip != NULL && IS_SNAPSHOT(ip) && ip->i_effnlink == 0) UFS_SNAPGONE(ip); return (error); } /* * Rewrite an existing directory entry to point at the inode * supplied. The parameters describing the directory entry are * set up by a call to namei. */ int ufs_dirrewrite(struct inode *dp, struct inode *oip, ino_t newinum, int newtype, u_int newparent) { struct buf *bp; struct direct *ep; struct vnode *vdp = ITOV(dp); int error; /* * Drop the link before we lock the buf so softdep can block if * necessary. */ oip->i_effnlink--; UFS_INODE_SET_FLAG(oip, IN_CHANGE); if (DOINGSOFTDEP(vdp)) { softdep_setup_unlink(dp, oip); } else { oip->i_nlink--; DIP_SET_NLINK(oip, oip->i_nlink); UFS_INODE_SET_FLAG(oip, IN_CHANGE); } error = UFS_BLKATOFF(vdp, (off_t)I_OFFSET(dp), (char **)&ep, &bp); if (error == 0 && ep->d_namlen == 2 && ep->d_name[1] == '.' && ep->d_name[0] == '.' && ep->d_ino != oip->i_number) { brelse(bp); error = EIDRM; } if (error) { oip->i_effnlink++; UFS_INODE_SET_FLAG(oip, IN_CHANGE); if (DOINGSOFTDEP(vdp)) { softdep_change_linkcnt(oip); } else { oip->i_nlink++; DIP_SET_NLINK(oip, oip->i_nlink); UFS_INODE_SET_FLAG(oip, IN_CHANGE); } return (error); } ep->d_ino = newinum; if (!OFSFMT(vdp)) ep->d_type = newtype; if (DOINGSOFTDEP(vdp)) { softdep_setup_directory_change(bp, dp, oip, newinum, newparent); bdwrite(bp); } else { if (DOINGASYNC(vdp)) { bdwrite(bp); error = 0; } else { error = bwrite(bp); } } UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE); /* * If the last named reference to a snapshot goes away, * drop its snapshot reference so that it will be reclaimed * when last open reference goes away. */ if (IS_SNAPSHOT(oip) && oip->i_effnlink == 0) UFS_SNAPGONE(oip); return (error); } /* * Check if a directory is empty or not. * Inode supplied must be locked. * * Using a struct dirtemplate here is not precisely * what we want, but better than using a struct direct. * * NB: does not handle corrupted directories. */ int ufs_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred, int skipwhiteout) { doff_t off; struct dirtemplate dbuf; struct direct *dp = (struct direct *)&dbuf; int error, namlen; ssize_t count; #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) for (off = 0; off < ip->i_size; off += dp->d_reclen) { error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, &count, (struct thread *)0); /* * Since we read MINDIRSIZ, residual must * be 0 unless we're at end of file. */ if (error || count != 0) return (0); /* avoid infinite loops */ if (dp->d_reclen == 0) return (0); /* skip empty entries */ if (dp->d_ino == 0 || (skipwhiteout != 0 && dp->d_ino == UFS_WINO)) continue; /* accept only "." and ".." */ # if (BYTE_ORDER == LITTLE_ENDIAN) if (OFSFMT(ITOV(ip))) namlen = dp->d_type; else namlen = dp->d_namlen; # else namlen = dp->d_namlen; # endif if (namlen > 2) return (0); if (dp->d_name[0] != '.') return (0); /* * At this point namlen must be 1 or 2. * 1 implies ".", 2 implies ".." if second * char is also "." */ if (namlen == 1 && dp->d_ino == ip->i_number) continue; if (dp->d_name[1] == '.' && dp->d_ino == parentino) continue; return (0); } return (1); } static int ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino, struct vnode **dd_vp) { struct dirtemplate dirbuf; struct vnode *ddvp; int error, namlen; ASSERT_VOP_LOCKED(vp, "ufs_dir_dd_ino"); *dd_vp = NULL; if (vp->v_type != VDIR) return (ENOTDIR); /* * First check to see if we have it in the name cache. */ if ((ddvp = vn_dir_dd_ino(vp)) != NULL) { KASSERT(ddvp->v_mount == vp->v_mount, ("ufs_dir_dd_ino: Unexpected mount point crossing")); *dd_ino = VTOI(ddvp)->i_number; *dd_vp = ddvp; return (0); } /* * Have to read the directory. */ error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL); if (error != 0) return (error); #if (BYTE_ORDER == LITTLE_ENDIAN) if (OFSFMT(vp)) namlen = dirbuf.dotdot_type; else namlen = dirbuf.dotdot_namlen; #else namlen = dirbuf.dotdot_namlen; #endif if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || dirbuf.dotdot_name[1] != '.') return (ENOTDIR); *dd_ino = dirbuf.dotdot_ino; return (0); } /* * Check if source directory is in the path of the target directory. */ int ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target, struct ucred *cred, ino_t *wait_ino) { struct mount *mp; struct vnode *tvp, *vp, *vp1; int error; ino_t dd_ino; vp = tvp = ITOV(target); mp = vp->v_mount; *wait_ino = 0; if (target->i_number == source_ino) return (EEXIST); if (target->i_number == parent_ino) return (0); if (target->i_number == UFS_ROOTINO) return (0); for (;;) { error = ufs_dir_dd_ino(vp, cred, &dd_ino, &vp1); if (error != 0) break; if (dd_ino == source_ino) { error = EINVAL; break; } if (dd_ino == UFS_ROOTINO) break; if (dd_ino == parent_ino) break; if (vp1 == NULL) { error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT, &vp1); if (error != 0) { *wait_ino = dd_ino; break; } } KASSERT(dd_ino == VTOI(vp1)->i_number, ("directory %ju reparented\n", (uintmax_t)VTOI(vp1)->i_number)); if (vp != tvp) vput(vp); vp = vp1; } if (error == ENOTDIR) panic("checkpath: .. not a directory\n"); if (vp1 != NULL) vput(vp1); if (vp != tvp) vput(vp); return (error); } #ifdef DIAGNOSTIC static void ufs_assert_inode_offset_owner(struct inode *ip, struct iown_tracker *tr, const char *name, const char *file, int line) { char msg[128]; snprintf(msg, sizeof(msg), "at %s@%d", file, line); ASSERT_VOP_ELOCKED(ITOV(ip), msg); MPASS((ip->i_mode & IFMT) == IFDIR); if (curthread == tr->tr_owner && ip->i_lock_gen == tr->tr_gen) return; printf("locked at\n"); stack_print(&tr->tr_st); printf("unlocked at\n"); stack_print(&tr->tr_unlock); panic("%s ip %p %jd offset owner %p %d gen %d " "curthread %p %d gen %d at %s@%d\n", name, ip, (uintmax_t)ip->i_number, tr->tr_owner, tr->tr_owner->td_tid, tr->tr_gen, curthread, curthread->td_tid, ip->i_lock_gen, file, line); } static void ufs_set_inode_offset_owner(struct inode *ip, struct iown_tracker *tr, const char *file, int line) { char msg[128]; snprintf(msg, sizeof(msg), "at %s@%d", file, line); ASSERT_VOP_ELOCKED(ITOV(ip), msg); MPASS((ip->i_mode & IFMT) == IFDIR); tr->tr_owner = curthread; tr->tr_gen = ip->i_lock_gen; stack_save(&tr->tr_st); } static void ufs_init_one_tracker(struct iown_tracker *tr) { tr->tr_owner = NULL; stack_zero(&tr->tr_st); } void ufs_init_trackers(struct inode *ip) { ufs_init_one_tracker(&ip->i_offset_tracker); ufs_init_one_tracker(&ip->i_count_tracker); ufs_init_one_tracker(&ip->i_endoff_tracker); } void ufs_unlock_tracker(struct inode *ip) { if (ip->i_count_tracker.tr_gen == ip->i_lock_gen) stack_save(&ip->i_count_tracker.tr_unlock); if (ip->i_offset_tracker.tr_gen == ip->i_lock_gen) stack_save(&ip->i_offset_tracker.tr_unlock); if (ip->i_endoff_tracker.tr_gen == ip->i_lock_gen) stack_save(&ip->i_endoff_tracker.tr_unlock); ip->i_lock_gen++; } doff_t ufs_get_i_offset(struct inode *ip, const char *file, int line) { ufs_assert_inode_offset_owner(ip, &ip->i_offset_tracker, "i_offset", file, line); return (ip->i_offset); } void ufs_set_i_offset(struct inode *ip, doff_t off, const char *file, int line) { ufs_set_inode_offset_owner(ip, &ip->i_offset_tracker, file, line); ip->i_offset = off; } int32_t ufs_get_i_count(struct inode *ip, const char *file, int line) { ufs_assert_inode_offset_owner(ip, &ip->i_count_tracker, "i_count", file, line); return (ip->i_count); } void ufs_set_i_count(struct inode *ip, int32_t cnt, const char *file, int line) { ufs_set_inode_offset_owner(ip, &ip->i_count_tracker, file, line); ip->i_count = cnt; } doff_t ufs_get_i_endoff(struct inode *ip, const char *file, int line) { ufs_assert_inode_offset_owner(ip, &ip->i_endoff_tracker, "i_endoff", file, line); return (ip->i_endoff); } void ufs_set_i_endoff(struct inode *ip, doff_t off, const char *file, int line) { ufs_set_inode_offset_owner(ip, &ip->i_endoff_tracker, file, line); ip->i_endoff = off; } #endif